001/** 
002 * Copyright (C) 2009 "Darwin V. Felix" <darwinfelix@users.sourceforge.net>
003 * 
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 * 
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012 * Lesser General Public License for more details.
013 * 
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this library; if not, write to the Free Software
016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017 */
018
019package net.sourceforge.spnego;
020
021/**
022 * Defines an object for performing user authorization (authZ). See the 
023 * javadoc of the {@link UserAccessControl} interface and the {@link LdapAccessControl} 
024 * class for more details about the default underlying implementation that 
025 * this interface relies upon.
026 * 
027 * <p>
028 * In simple terms, roles are attributes that belong to a user and that an attribute 
029 * is something that MUST exist in an attribute set. This treatment is somewhat similar 
030 * to the traditional sense that users are assigned roles and/or role_groups. 
031 * </p>
032 * 
033 * <p>
034 * One dissimilarity is that an attribute MUST exist in an attribute set. Another is   
035 * that users are defined only by their attributes and not by their attribute sets. 
036 * This is in contrast to the role based approach where roles do not have to belong 
037 * to a role_group.  In addition, a role_group can be concretely assigned to a user, 
038 * whereas an attribute set can NOT be concretely assigned to a user.
039 * </p>
040 * 
041 * <p>
042 * Some example attribute sets within an Organization might include: Job Title, 
043 * Company Department, Company Division, Company Location, Active Directory 
044 * Group, Email Distribution List, etc. An attribute set is unique within the set 
045 * of all attribute sets. An attribute MUST exist in only one attribute set. Hence, an 
046 * example where job titles might include titles such as Developer, Manager, 
047 * Analyst, HR Admin, Account Executive, and Receptionist, any and all job titles 
048 * MUST exist in only one attribute set AND they MUST all be in the same attribute set.
049 * </p>
050 * 
051 * <p>
052 * In the example above, the source of attribute information is defined as 
053 * existing in an LDAP/Active Directory Group, User Department, Email Distribution 
054 * List, etc. A policy is configured to search one of these attribute sets or optionally 
055 * to search all of these attribute sets. The attribute sets can be mixed to allow 
056 * for a more expressive policy statement. e.g. 1) A user has access if they are 
057 * in <i>this</i> AD Group and belong in one of <i>these</i> departments, or 
058 * 2) a user has access if they are in <i>this</i> email distribution list 
059 * and in one of <i>these</i> AD Groups or is in one <i>these</i> departments, 
060 * or 3) a user can see <i>the edit button</i> if they are in <i>this</i> 
061 * AD Group and in one of <i>these</i> other AD Groups.
062 * </p>
063 * 
064 * <p>
065 * <b>Attribute Set Example Scenario:</b><br />
066 * This example will assume Active Directory (AD) as the data store for user information. 
067 * It also assumes that in AD there are three AD Groups named <code>File Share Access</code>, 
068 * <code>Finance London</code>, and <code>Desktop Support</code>. Finally, we assume
069 * that the department attribute in AD's user profile is populated 
070 * for each user. Example values in the department attribute set might be 
071 * <code>IT</code>, <code>Accounting</code>, or <code>HR</code>. Under this scenario, 
072 * AD Group would be one attribute set and department would be another attribute set. 
073 * </p>
074 * 
075 * <p>
076 * Notice that you concretely assign an attribute (e.g. <code>Accounting</code>) to a 
077 * user but you can't assign an attribute set (e.g. department to a user). For example, 
078 * the attribute set department contains many attributes within it: <code>IT</code>, 
079 * <code>Accounting</code>, and <code>HR</code>. 
080 * </p>
081 * 
082 * <p>
083 * <b>Example Usage 1:</b><br />
084 * A web application/service requires authentication (authN) but certain areas 
085 * must only be accessed by users who are in the <code>HR</code> department 
086 * OR have been added to the AD Group named <code>File Share Access</code> 
087 * OR those users who have a value of <code>Desktop Support</code> 
088 * in their department attribute in AD.
089 * 
090 * <pre>
091 * boolean hasPermission = false;
092 * 
093 * String[] attributes = new String[] {"HR", "File Share Access", "Desktop Support"};
094 * 
095 * if (request instanceof SpnegoAccessControl) {
096 *     SpnegoAccessControl accessControl = (SpnegoAccessControl) request;
097 *     
098 *     hasPermission = accessControl.anyRole(attributes);
099 * } 
100 * </pre>
101 * 
102 * In the above example, the method call <code>anyRole</code> will return true 
103 * if the user is in the department named HR or the AD Group named "File share Access" 
104 * or is in the department named "Desktop Support".
105 * </p>
106 * 
107 * <p>
108 * <b>Example Usage 2:</b></br />
109 * Certain areas of a web application/service must only be accessed by users who are 
110 * in the AD Group <code>File Share Access</code> AND who are in the AD Group 
111 * <code>Finance London</code> or who are in the <code>Accounting</code> department.
112 * 
113 * <pre>
114 * boolean hasPermission = false;
115 * 
116 * String attributeX = "File Share Access";
117 * String[] arttributeYs = new String[] {"Finance London", "Accounting"};
118 * 
119 * if (request instanceof SpnegoAccessControl) {
120 *     SpnegoAccessControl accessControl = (SpnegoAccessControl) request;
121 *     
122 *     hasPermission = accessControl.hasRole(attributeX, attributeYs);
123 * } 
124 * </pre>
125 * 
126 * In the above example, if the user has the attribute File Share Access  
127 * AND one of the attributeYs (Finance London or Accounting), the method call 
128 * <code>hasRole</code> will return true. 
129 * </p>
130 * 
131 * <p>
132 * <b>User-defined Resource Label Example:</b>
133 * </p>
134 * 
135 * <p>
136 * An alternative to specifying department names, groups, email distribution lists, etc. 
137 * is to use a user-defined resource label. Resource labels are optional and hence must  
138 * undergo additional configuration before use.   
139 *
140 * <pre>
141 * boolean hasPermission = false;
142 * 
143 * if (request instanceof SpnegoAccessControl) {
144 *     SpnegoAccessControl accessControl = (SpnegoAccessControl) request;
145 *     
146 *     hasPermission = accessControl.hasAccess("finance-links");
147 * } 
148 * </pre>
149 * </p>
150 * 
151 * <p>
152 * In the above example, the attribute(s) that support the policy is abstracted by the 
153 * user-defined resource label named finance-links. Concretely, given the previous example, 
154 * the resource label finance-links would be assigned the attributes File Share Access, 
155 * Finance London, and Accounting.
156 * </p>
157 * 
158 * <p>
159 * <b>The Java HttpServletRequest Interface and it's isUserInRole method</b>
160 * </p>
161 * <p>
162 * In addition to how the {@link javax.servlet.http.HttpServletRequest} interface 
163 * defines a <code>getRemoteUser</code> method to retrieve the name of the authenticated 
164 * (authN) user, the {@link javax.servlet.http.HttpServletRequest} interface also defines 
165 * an <code>isUserInRole</code> method that  
166 * "<i>returns a boolean indicating whether the authenticated user is included in the 
167 * specified logical 'role'</i>". In all of the examples above, a Java Cast was 
168 * necessary to achieve the functionality of the <code>SpnegoAccessControl</code> 
169 * interface. However, the <code>isUserInRole</code> method obviates the need to perform a 
170 * Java Cast.
171 * </p>
172 * 
173 * <p>
174 * <b>No java cast example:</b><br />
175 * 
176 * <pre>
177 * boolean hasPermission = request.isUserInRole("File Share Access");
178 * </pre>
179 * </p>
180 * 
181 * <p>
182 * In the above example, the Java Cast was not necessary because the standard 
183 * <code>HttpServletRequest</code> Interface defines the <code>isUserInRole</code> 
184 * method and the SPNEGO Library implements the <code>isUserInRole</code> method of 
185 * the interface. Although convenient, available, and performs as expected, 
186 * the <code>isUserInRole</code> method alone may not be as expressive as the 
187 * methods defined in the <code>SpnegoAccessControl</code> interface.  
188 * </p>
189 * 
190 * <p>
191 * For more information regarding implementation details, 
192 * as well as additional usage examples, please see the javadoc for the 
193 * {@link UserAccessControl} interface as well as the javadoc for the 
194 * {@link LdapAccessControl} class.
195 * </p>
196 * 
197 * <p>
198 * Also, take a look at the <a href="http://spnego.sourceforge.net/reference_docs.html" 
199 * target="_blank">reference docs</a> for a complete list of configuration parameters.
200 * </p>
201 * 
202 * <p>
203 * Finally, to see a working example and instructions, take a look at the 
204 * <a href="http://spnego.sourceforge.net/enable_authZ_ldap.html" 
205 * target="_blank">enable authZ with LDAP</a> guide. 
206 * </p>
207 * 
208 * 
209 * @author Darwin V. Felix
210 *
211 */
212public interface SpnegoAccessControl {
213
214    /**
215     * Checks to see if the user has at least one of the passed-in attributes.
216     * 
217     * <pre>
218     * String[] attributes = new String[] {"Developer", "Los Angeles", "Manager"};
219     * 
220     * if (accessControl.anyRole(attributes)) {
221     *     // will be in here if the user has at least one matching attribute
222     * }
223     * </pre>
224     * 
225     * @param attributes e.g. Team Lead, IT, Developer
226     * @return true if the user has at least one of the passed-in roles/features
227     */
228    boolean anyRole(final String... attributes);
229    
230    /**
231     * Checks to see if the user has the passed-in attribute.
232     * 
233     * <pre>
234     * String attribute = "Developer";
235     * 
236     * if (accessControl.hasRole(attribute)) {
237     *     // will be in here if the user has the matching attribute
238     * }
239     * </pre>
240     * 
241     * @param attribute e.g. Team Lead, IT, Developer
242     * @return true if the user has at least one of the passed-in roles/features 
243     */
244    boolean hasRole(final String attribute);
245
246    /**
247     * Checks to see if the user has the first attribute   
248     * AND has at least one of the passed-in attributes.
249     * 
250     * <pre>
251     * String attributeX = "Los Angeles";
252     * String[] attributeYs = new String[] {"Developer", "Manager"};
253     * 
254     * if (accessControl.hasRole(attributeX, attributeYs)) {
255     *     // will be in here if the user has attributeX 
256     *     // AND has at least one of the attributeYs.
257     * }
258     * </pre>
259     * 
260     * @param attributeX e.g. Information Technology
261     * @param attributeYs e.g. Team Lead, IT-Architecture-DL
262     * @return true if the user has featureX AND at least one the featureYs
263     */
264    boolean hasRole(final String attributeX, final String... attributeYs); 
265    
266    /**
267     * Checks to see if the user has at least one of the passed-in user-defined 
268     * resource labels
269     * 
270     * <pre>
271     * String[] resources = new String[] {"admin-links", "ops-buttons"};
272     * 
273     * if (accessControl.anyAccess(resources)) {
274     *     // will be in here if the user has at least one matching resource
275     * }
276     * </pre>
277     * 
278     * @param resources e.g. admin-links, ops-buttons
279     * @return true if the user has at least one of the passed-in resources
280     */
281    boolean anyAccess(final String... resources);
282    
283    /**
284     * Checks to see if the user has access to the user-defined resource label.
285     * 
286     * <pre>
287     * boolean hasPermission = false;
288     * 
289     * if (request instanceof SpnegoAccessControl) {
290     *     SpnegoAccessControl accessControl = (SpnegoAccessControl) request;
291     *     
292     *     hasPermission = accessControl.hasAccess("finance-links");
293     * } 
294     * </pre>
295     * 
296     * @param resource e.g. admin-buttons
297     * @return true if the user has access to the user-defined resource
298     */
299    boolean hasAccess(final String resource);
300    
301    /**
302     * Checks to see if the user has the first user-defined resource label   
303     * AND has at least one of the passed-in user-defined resource labels.
304     * 
305     * <pre>
306     * String resourceX = "finance-links";
307     * String[] resourceYs = new String[] {"admin-links", "accounting-buttons"};
308     * 
309     * if (accessControl.hasAccess(resourceX, resourceYs)) {
310     *     // will be in here if the user has resourceX 
311     *     // AND has at least one of the resourceYs.
312     * }
313     * </pre>
314     * 
315     * @param resourceX e.g. finance-links
316     * @param resourceYs e.g. admin-links, accounting-buttons
317     * @return true if the user has resourceX AND at least one the resourceYs
318     */
319    boolean hasAccess(final String resourceX, final String... resourceYs);
320    
321    /**
322     * Returns the user's info object.
323     * 
324     * @return the user's info object
325     */
326    UserInfo getUserInfo();
327}