0da95eb45e871540ed014f5899b9a86132fff009
[moon.git] /
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.aaa.shiro.authorization;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Sets;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.HashSet;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 /**
19  * A container for RBAC Rules. An RBAC Rule is composed of a url pattern which
20  * may contain asterisk characters (*), and a collection of roles. These are
21  * represented in shiro.ini in the following format:
22  * <code>urlPattern=roles[atLeastOneCommaSeperatedRole]</code>
23  *
24  * RBACRules are immutable; that is, you cannot change the url pattern or the
25  * roles after creation. This is done for security purposes. RBACRules are
26  * created through utilizing a static factory method:
27  * <code>RBACRule.createRBACRule()</code>
28  *
29  * @author Ryan Goulding (ryandgoulding@gmail.com)
30  *
31  */
32 public class RBACRule {
33
34     private static final Logger LOG = LoggerFactory.getLogger(RBACRule.class);
35
36     /**
37      * a url pattern that can optional contain asterisk characters (*)
38      */
39     private String urlPattern;
40
41     /**
42      * a collection of role names, such as "admin" and "user"
43      */
44     private Collection<String> roles = new HashSet<String>();
45
46     /**
47      * Creates an RBAC Rule. Made private for static factory method.
48      *
49      * @param urlPattern
50      *            Cannot be null or the empty string.
51      * @param roles
52      *            Must contain at least one role.
53      * @throws NullPointerException
54      *             if <code>urlPattern</code> or <code>roles</code> is null
55      * @throws IllegalArgumentException
56      *             if <code>urlPattern</code> is an empty string or
57      *             <code>roles</code> is an empty collection.
58      */
59     private RBACRule(final String urlPattern, final Collection<String> roles)
60             throws NullPointerException, IllegalArgumentException {
61
62         this.setUrlPattern(urlPattern);
63         this.setRoles(roles);
64     }
65
66     /**
67      * The static factory method used to create RBACRules.
68      *
69      * @param urlPattern
70      *            Cannot be null or the empty string.
71      * @param roles
72      *            Cannot be null or an emtpy collection.
73      * @return An immutable RBACRule
74      */
75     public static RBACRule createAuthorizationRule(final String urlPattern,
76             final Collection<String> roles) {
77
78         RBACRule authorizationRule = null;
79         try {
80             authorizationRule = new RBACRule(urlPattern, roles);
81         } catch (Exception e) {
82             LOG.error("Cannot instantiate the AuthorizationRule", e);
83         }
84         return authorizationRule;
85     }
86
87     /**
88      *
89      * @return the urlPattern for the RBACRule
90      */
91     public String getUrlPattern() {
92         return urlPattern;
93     }
94
95     /*
96      * helper to ensure the url pattern is not the empty string
97      */
98     private static void checkUrlPatternLength(final String urlPattern)
99             throws IllegalArgumentException {
100
101         final String EXCEPTION_MESSAGE = "Empty String is not allowed for urlPattern";
102         if (urlPattern.isEmpty()) {
103             throw new IllegalArgumentException(EXCEPTION_MESSAGE);
104         }
105     }
106
107     private void setUrlPattern(final String urlPattern) throws NullPointerException,
108             IllegalArgumentException {
109
110         Preconditions.checkNotNull(urlPattern);
111         checkUrlPatternLength(urlPattern);
112         this.urlPattern = urlPattern;
113     }
114
115     /**
116      *
117      * @return a copy of the rule, so any modifications to the returned
118      *         reference do not affect the immutable <code>RBACRule</code>.
119      */
120     public Collection<String> getRoles() {
121         // Returns a copy of the roles collection such that the original set
122         // keeps
123         // its contract of remaining immutable.
124         //
125         // Since this method is only called at shiro initialiation time,
126         // memory consumption of creating a new set is a non-issue.
127         return Sets.newHashSet(roles);
128     }
129
130     /*
131      * check to ensure the roles collection is not empty
132      */
133     private static void checkRolesCollectionSize(final Collection<String> roles)
134             throws IllegalArgumentException {
135
136         final String EXCEPTION_MESSAGE = "roles must contain at least 1 role";
137         if (roles.isEmpty()) {
138             throw new IllegalArgumentException(EXCEPTION_MESSAGE);
139         }
140     }
141
142     private void setRoles(final Collection<String> roles) throws NullPointerException,
143             IllegalArgumentException {
144
145         Preconditions.checkNotNull(roles);
146         checkRolesCollectionSize(roles);
147         this.roles = roles;
148     }
149
150     /**
151      * Generates a string representation of the <code>RBACRule</code> roles in
152      * shiro form.
153      *
154      * @return roles string representation in the form
155      *         <code>roles[roleOne,roleTwo]</code>
156      */
157     public String getRolesInShiroFormat() {
158         final String ROLES_STRING = "roles";
159         return ROLES_STRING + Arrays.toString(roles.toArray());
160     }
161
162     /**
163      * Generates the string representation of the <code>RBACRule</code> in shiro
164      * form. For example: <code>urlPattern=roles[admin,user]</code>
165      */
166     @Override
167     public String toString() {
168         return String.format("%s=%s", urlPattern, getRolesInShiroFormat());
169     }
170 }