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