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