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}