c68457559a42892ca2e3aa8739ee34ea88e41b73
[utils] / security / impl / src / main / java / org / wamblee / security / authorization / UrlAuthorizationRule.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */ 
16 package org.wamblee.security.authorization;
17
18 import static org.wamblee.security.authorization.AuthorizationResult.*;
19
20 import javax.persistence.Access;
21 import javax.persistence.AccessType;
22 import javax.persistence.CascadeType;
23 import javax.persistence.Column;
24 import javax.persistence.Entity;
25 import javax.persistence.JoinColumn;
26 import javax.persistence.OneToOne;
27 import javax.persistence.Transient;
28
29 import org.apache.log4j.Logger;
30 import org.wamblee.security.authentication.UserAdministration;
31
32 /**
33  * Utility base class for implementation of authentication rules based on the
34  * <ul>
35  * <li>The path of the resource. To obtain the path of a resource, subclasses
36  * must implement {@link #getResourcePath(Object)}. Whether a path is
37  * appropriate is determined by a
38  * {@link org.wamblee.security.authorization.AbstractPathCondition}.</li>
39  * <li>The user identity with which the resource is accessed. Whether a user is
40  * appropriate is determined by a
41  * {@link org.wamblee.security.authorization.AbstractUserCondition}.</li>
42  * <li>The operation that is requested. Whether the operation is appropriate is
43  * determined by a {@link org.wamblee.security.authorization.AbstractOperationCondition}
44  * .</li>
45  * </ul>
46  * In case all three conditions match, the condition returns the configured
47  * result passed at construction (GRANTED or DENIED). If the resource is not of
48  * the specified type, the result is UNSUPPORTED_RESOURCE, otherwise, the result
49  * is UNDECIDED.
50  */
51 @Entity
52 @Access(AccessType.PROPERTY)
53 public abstract class UrlAuthorizationRule extends AbstractAuthorizationRule {
54     private static final Logger LOGGER = Logger
55         .getLogger(UrlAuthorizationRule.class);
56
57     /**
58      * Result that the rule will return in case there is a match.
59      */
60     private AuthorizationResult result;
61
62     /**
63      * A condition which specifies which users the rule is for.
64      */
65     private UserCondition userCondition;
66
67     /**
68      * Path the rule applies for.
69      */
70     private PathCondition pathCondition;
71
72     /**
73      * Resource class that the rule applies for.
74      */
75     private Class resourceClass;
76
77     /**
78      * Operation that this rule is for.
79      */
80     
81     private OperationCondition operationCondition;
82
83     /**
84      * Constructs an authorization rule. IF the group and path match, then the
85      * provided result will be returned.
86      * 
87      * @param aResult
88      *            Result of the authorization when the path and group match.
89      * @param aUserCondition
90      *            Condition to match users.
91      * @param aPathCondition
92      *            Condition to match paths with.
93      * @param aResourceClass
94      *            Supported resource class this is for.
95      * @param aOperationCondition
96      *            Condition to match the operation with.
97      */
98     protected UrlAuthorizationRule(AuthorizationResult aResult,
99         UserCondition aUserCondition, PathCondition aPathCondition,
100         Class aResourceClass, OperationCondition aOperationCondition) {
101         if (!aResult.equals(GRANTED) && !aResult.equals(DENIED)) {
102             throw new IllegalArgumentException(
103                 "Only GRANTED or DENIED may be used: " + aResult);
104         }
105
106         result = aResult;
107         userCondition = aUserCondition;
108         pathCondition = aPathCondition;
109         resourceClass = aResourceClass;
110         operationCondition = aOperationCondition;
111     }
112
113     /**
114      * For OR mapping.
115      * 
116      */
117     protected UrlAuthorizationRule(Class aResourceClass) {
118         result = null;
119         userCondition = null;
120         pathCondition = null;
121         resourceClass = aResourceClass;
122         operationCondition = null;
123     }
124
125     /**
126      * For OR mapping.
127      * 
128      */
129     protected UrlAuthorizationRule() {
130         result = null;
131         userCondition = null;
132         pathCondition = null;
133         resourceClass = null;
134         operationCondition = null;
135     }
136
137     /*
138      * (non-Javadoc)
139      * 
140      * @see
141      * org.wamblee.security.authorization.AuthorizationRule#getSupportedTypes()
142      */
143     @Transient
144     public Class[] getSupportedTypes() {
145         return new Class[] { resourceClass };
146     }
147
148     /*
149      * (non-Javadoc)
150      * 
151      * @see
152      * org.wamblee.security.authorization.AuthorizationRule#isAllowed(java.lang
153      * .Object, org.wamblee.security.authorization.Operation)
154      */
155     public AuthorizationResult isAllowed(Object aResource,
156         Operation aOperation, String aUser) {
157         if (!resourceClass.isInstance(aResource)) {
158             return UNSUPPORTED_RESOURCE;
159         }
160
161         String path = getResourcePath(aResource);
162
163         return isAllowedWithPath(path, aOperation, aUser);
164     }
165
166     /**
167      * Determines if the operation is allowed on the resource.
168      * 
169      * @param aPath
170      *            Path of the resource.
171      * @param aOperation
172      *            Operation to be done.
173      * @param aUser
174      *            Currently logged in user or null if no user is logged in.
175      * 
176      * @return Authorization result,
177      */
178     protected AuthorizationResult isAllowedWithPath(String aPath, Operation aOperation,
179         String aUser) {
180         if (!pathCondition.matches(aPath)) {
181             return UNDECIDED;
182         }
183
184         if (!operationCondition.matches(aOperation)) {
185             return UNDECIDED;
186         }
187
188         if (!userCondition.matches(aUser)) {
189             return UNDECIDED;
190         }
191
192         return result;
193     }
194
195     /**
196      * Gets the path of the resource.
197      * 
198      * @param aResource
199      *            Resource, guaranteed to be an instance of
200      *            {@link #resourceClass}.
201      * 
202      * @return Path of the resource.
203      */
204     protected abstract String getResourcePath(Object aResource);
205
206     /*
207      * (non-Javadoc)
208      * 
209      * @see java.lang.Object#toString()
210      */
211     @Override
212     public String toString() {
213         return "UrlAUthorizationRule(result = " + result +
214             ", pathCondition = " + pathCondition + ", userCondition = " +
215             userCondition + ", resourceClass = " + resourceClass + ")";
216     }
217
218     /**
219      * Gets the authorization result for OR mapping.
220      * 
221      * @return Result.
222      */
223     @Column(name = "AUTH_RESULT", nullable = false)
224     protected String getAuthorizationResultString() {
225         if (result == null) {
226             return null;
227         }
228
229         return result.toString();
230     }
231
232     /**
233      * Sets the authorization result, for OR mapping.
234      * 
235      * @param aResult
236      *            Result.
237      */
238     protected void setAuthorizationResultString(String aResult) {
239         result = AuthorizationResult.valueOf(aResult);
240     }
241
242     @Column(name = "RES_CLASSNAME", nullable = false)
243     protected String getResourceClassName() {
244         if (resourceClass == null) {
245             return "";
246         }
247
248         return resourceClass.getName();
249     }
250
251     protected void setResourceClassName(String aResourceClass) {
252         try {
253             resourceClass = Class.forName(aResourceClass);
254         } catch (ClassNotFoundException e) {
255             LOGGER.error("Cannot find resource class '" + aResourceClass + "'",
256                 e);
257             throw new IllegalArgumentException(e.getMessage(), e);
258         }
259     }
260
261     /**
262      * 
263      * @return Returns the operationCondition.
264      */
265     @OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractOperationCondition.class, orphanRemoval = true)
266     @JoinColumn(name = "OPER_COND_PK")
267     public OperationCondition getOperationCondition() {
268         return operationCondition;
269     }
270
271     /**
272      * 
273      * @param aOperationCondition
274      *            The operationCondition to set.
275      */
276     protected void setOperationCondition(OperationCondition aOperationCondition) {
277         operationCondition = aOperationCondition;
278     }
279
280     /**
281      * 
282      * @return Returns the pathCondition.
283      */
284     @OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractPathCondition.class, orphanRemoval = true)
285     @JoinColumn(name = "PATH_COND_PK")
286     public PathCondition getPathCondition() {
287         return pathCondition;
288     }
289
290     /**
291      * 
292      * @param aPathCondition
293      *            The pathCondition to set.
294      */
295     protected void setPathCondition(PathCondition aPathCondition) {
296         pathCondition = aPathCondition;
297     }
298
299     /**
300      * 
301      * @return Returns the userCondition.
302      */
303     @OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractUserCondition.class, orphanRemoval = true)
304     @JoinColumn(name = "USER_COND_PK")
305     public UserCondition getUserCondition() {
306         return userCondition;
307     }
308
309     /**
310      * 
311      * @param aUserCondition
312      *            The userCondition to set.
313      */
314     protected void setUserCondition(UserCondition aUserCondition) {
315         userCondition = aUserCondition;
316     }
317     
318     @Override
319     public void setUserAdministration(UserAdministration aAdmin) {
320         userCondition.setUserAdmin(aAdmin);   
321     }
322
323 }