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