001package de.deepamehta.core.service.accesscontrol;
002
003import de.deepamehta.core.Association;
004import de.deepamehta.core.DeepaMehtaObject;
005import de.deepamehta.core.RelatedTopic;
006import de.deepamehta.core.Topic;
007
008import javax.servlet.http.HttpServletRequest;
009import javax.servlet.http.HttpSession;
010
011import java.util.concurrent.Callable;
012
013
014
015public interface AccessControl {
016
017
018
019    // === Permissions ===
020
021    /**
022     * Checks if a user is permitted to perform an operation on an object (topic or association).
023     *
024     * @param   username    the logged in user, or <code>null</code> if no user is logged in.
025     * @param   objectId    a topic ID, or an association ID.
026     *
027     * @return  <code>true</code> if permission is granted, <code>false</code> otherwise.
028     */
029    boolean hasPermission(String username, Operation operation, long objectId);
030
031    // ---
032
033    boolean hasReadPermission(String username, long workspaceId);
034
035    boolean hasWritePermission(String username, long workspaceId);
036
037
038
039    // === User Accounts ===
040
041    /**
042     * Checks if the given credentials are valid.
043     *
044     * @return  the corresponding Username topic if the credentials are valid, or <code>null</code> otherwise.
045     */
046    Topic checkCredentials(Credentials cred);
047
048    /**
049     * Changes the password of an existing user account.
050     * <p>
051     * This is a privileged method: it works also if the respective user is not logged in.
052     *
053     * @param   cred    the username and new password.
054     *                  An user account with the given username must exist. (The username can't be changed.)
055     */
056    void changePassword(Credentials cred);
057
058    // ---
059
060    /**
061     * Returns the Username topic that corresponds to a username.
062     *
063     * @return  the Username topic, or <code>null</code> if no such Username topic exists.
064     */
065    Topic getUsernameTopic(String username);
066
067    /**
068     * Returns the private workspace of the given user.
069     * <p>
070     * Note: a user can have more than one private workspace. The workspace returned
071     * by this method is the one that holds the user's password topic.
072     * <p>
073     * This is a privileged method, it bypasses the access control system.
074     */
075    Topic getPrivateWorkspace(String username);
076
077    /**
078     * Checks if a user is a member of a given workspace.
079     *
080     * @param   username    the logged in user, or <code>null</code> if no user is logged in.
081     */
082    boolean isMember(String username, long workspaceId);
083
084    /**
085     * Returns the creator of a topic or an association.
086     *
087     * @return  The username of the creator, or <code>null</code> if no creator is set.
088     */
089    String getCreator(long objectId);
090
091
092
093    // === Session ===
094
095    /**
096     * Returns the username that is associated with a request.
097     *
098     * @return  the username, or <code>null</code> if no user is associated with the request.
099     */
100    String getUsername(HttpServletRequest request);
101
102    /**
103     * Convenience method that returns the Username topic that corresponds to a request.
104     * Basically it calls <code>getUsernameTopic(getUsername(request))</code>.
105     *
106     * @return  the Username topic, or <code>null</code> if no user is associated with the request.
107     */
108    Topic getUsernameTopic(HttpServletRequest request);
109
110    String username(HttpSession session);
111
112
113
114    // === Workspaces / Memberships ===
115
116    /**
117     * Returns a workspace by URI.
118     * <p>
119     * This is a privileged method: it works also if the current user has no READ permission for the workspace.
120     *
121     * @return  The workspace (a topic of type "Workspace").
122     *
123     * @throws  RuntimeException    If no workspace exists for the given URI.
124     */
125    Topic getWorkspace(String uri);
126
127    // ---
128
129    /**
130     * Returns the ID of the "DeepaMehta" workspace.
131     */
132    long getDeepaMehtaWorkspaceId();
133
134    /**
135     * Returns the ID of the "Administration" workspace.
136     */
137    long getAdministrationWorkspaceId();
138
139    /**
140     * Returns the ID of the "System" workspace.
141     */
142    long getSystemWorkspaceId();
143
144    // ---
145
146    /**
147     * Returns the ID of the workspace a topic or association is assigned to.
148     *
149     * @param   objectId    a topic ID, or an association ID
150     *
151     * @return  The workspace ID, or <code>-1</code> if no workspace is assigned.
152     */
153    long getAssignedWorkspaceId(long objectId);
154
155    /**
156     * Performs the initial workspace assignment for an object.
157     * <p>
158     * Use this method only for objects which have no workspace assignment already, that is e.g. objects
159     * created in a migration or objects created while workspace assignment is deliberately suppressed.
160     */
161    void assignToWorkspace(DeepaMehtaObject object, long workspaceId);
162
163    /**
164     * Checks if an association represents a workspace assignment.
165     * <p>
166     * This is a privileged method: it works also if the current user has no READ permission for the potential
167     * workspace.
168     */
169    boolean isWorkspaceAssignment(Association assoc);
170
171    // ---
172
173    /**
174     * Runs a code block while suppressing the standard workspace assignment for all topics/associations
175     * created within that code block.
176     */
177    <V> V runWithoutWorkspaceAssignment(Callable<V> callable) throws Exception;
178
179    /**
180     * Returns true if standard workspace assignment is currently suppressed for the current thread.
181     */
182    boolean workspaceAssignmentIsSuppressed();
183
184
185
186    // === Config Service ===
187
188    /**
189     * Returns the configuration topic of the given type for the given topic.
190     * <p>
191     * This is a privileged method, it bypasses the access control system.
192     *
193     * @throws  RuntimeException    if no such configuration topic exists.
194     */
195    RelatedTopic getConfigTopic(String configTypeUri, long topicId);
196
197
198
199    // === Email Addresses ===
200
201    /**
202     * Returns the username for the given email address.
203     * <p>
204     * The username is determined by traversing from the Email Address topic along a
205     * <code>org.deepamehta.signup.user_mailbox</code> association.
206     * <p>
207     * This is a privileged method, it bypasses the access control system.
208     *
209     * @throws  RuntimeException    if no such Email Address topic exists in the DB, or
210     *                              if more than one such Email Address topics exist in the DB, or
211     *                              if the Email Address topic is not associated to a Username topic.
212     */
213    String getUsername(String emailAddress);
214
215    /**
216     * Returns the email address for the given username.
217     * <p>
218     * The email address is determined by traversing from the Username topic along a
219     * <code>org.deepamehta.signup.user_mailbox</code> association.
220     * <p>
221     * This is a privileged method, it bypasses the access control system.
222     *
223     * @throws  RuntimeException    if no such Username topic exists in the DB, or
224     *                              if the Username topic is not associated to an Email Address topic.
225     */
226    String getEmailAddress(String username);
227
228    // ---
229
230    /**
231     * Returns true if an "Email Address" (dm4.contacts.email_address) topic with the given value exists,
232     * false otherwise.
233     * <p>
234     * This is a privileged method, it bypasses the access control system.
235     */
236    boolean emailAddressExists(String emailAddress);
237}