introducing interface IGrantedAuthorityConverter
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / hibernate / permission / CdmAuthority.java
1 /**
2 * Copyright (C) 2012 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.persistence.hibernate.permission;
10
11 import java.util.EnumSet;
12 import java.util.UUID;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
15
16 import org.apache.log4j.Logger;
17 import org.springframework.security.access.ConfigAttribute;
18 import org.springframework.security.core.GrantedAuthority;
19
20 import eu.etaxonomy.cdm.model.common.CdmBase;
21 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
22
23 import sun.security.provider.PolicyParser.ParsingException;
24
25 /**
26 * A <code>CdmAuthority</code> consists basically of two parts which are separated
27 * by a dot character '.'.
28 *
29 * <ul>
30 * <li><code>permissionClass</code>: an {@link CdmPermissionClass} instance with represents a cdm
31 * type or a part of the cdm type hierarchy. The className is always represented
32 * as an upper case string.</li>
33 * <li><code>property</code>: The <code>CdmAuthority</code> only applies to instances
34 * which satisfy the specified property. Interpretation is up to type specific voters.</li>
35 * <li><code>operation</code>: a string which specifies a {@link Operation} on that set of cdm
36 * types</li>
37 * <li><code>targetUuid</code>: The <code>operation</code> may be restricted to a specific cdm entity by adding
38 * the entity uuid to the <code>operation</code>. The uuid string is enclosed in curly brackets '<code>{</code>'
39 * , '<code>}</code>' and appended to the end of the <code>operation</code>.</li>
40 * </ul>
41 *
42 * <h3>Examples for permissionStrings</h3>
43 *
44 * <pre>
45 * TAXONBASE.CREATE
46 * TAXONBASE.READ
47 * TAXONBASE.UPDATE
48 * TAXONBASE.DELETE
49 * DESCRIPTIONBASE.UPDATE
50 * DESCRIPTIONELEMENTBASE(Ecology).UPDATE
51 * TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}
52 * </pre>
53 *
54 * The method {@link #getPermissionString(String)} parses a full authority and returns permissionString and
55 * the {@link CdmAuthority} from the <code>authority</code>.
56 *
57 *
58 * @author k.luther
59 */
60 public class CdmAuthority implements GrantedAuthority, ConfigAttribute, IGrantedAuthorityConverter {
61
62 private static final long serialVersionUID = 1L;
63
64 public static final Logger logger = Logger.getLogger(CdmAuthority.class);
65
66 CdmPermissionClass permissionClass;
67 String property;
68 EnumSet<CRUD> operation;
69 UUID targetUuid;
70
71 public CdmAuthority(CdmBase targetDomainObject, EnumSet<CRUD> operation, UUID uuid){
72 this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);
73 this.property = null;
74 this.operation = operation;
75 this.targetUuid = uuid;
76 }
77
78 public CdmAuthority(CdmBase targetDomainObject, String property, EnumSet<CRUD> operation, UUID uuid){
79 this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);
80 this.property = property;
81 this.operation = operation;
82 this.targetUuid = uuid;
83 }
84
85
86 public CdmAuthority(CdmPermissionClass permissionClass, String property, EnumSet<CRUD> operation, UUID uuid){
87 this.permissionClass = permissionClass;
88 this.property = property;
89 this.operation = operation;
90 this.targetUuid = uuid;
91 }
92
93 private CdmAuthority (String authority) throws ParsingException{
94
95 String[] tokens = parse(authority);
96 // className must never be null
97 permissionClass = CdmPermissionClass.valueOf(tokens[0]);
98 property = tokens[1];
99 if(tokens[2] != null){
100 try {
101 operation = Operation.fromString(tokens[2]);
102 } catch (IllegalArgumentException e) {
103 logger.warn("cannot parse Operation " + tokens[2]);
104 throw e;
105 }
106 }
107 if(tokens[3] != null){
108 targetUuid = UUID.fromString(tokens[3]);
109 }
110 }
111
112 public CdmPermissionClass getPermissionClass(){
113 return permissionClass;
114 }
115
116 public String getProperty(){
117 return property;
118 }
119
120 public EnumSet<CRUD> getOperation(){
121 return operation;
122 }
123
124 public UUID getTargetUUID(){
125 return targetUuid;
126 }
127
128 public boolean hasTargetUuid() {
129 return targetUuid != null;
130 }
131
132 public boolean hasProperty() {
133 return property != null;
134 }
135
136 /**
137 * Parses the given <code>authority</code> and returns an array of tokens.
138 * The array has a length of four elements whereas the elements can be null.
139 * The elements in the array correspond to the fields of {@link CdmAuthority}:
140 * <ol>
141 * <li>{@link CdmAuthority#permissionClass}</li>
142 * <li>{@link CdmAuthority#property}</li>
143 * <li>{@link CdmAuthority#operation}</li>
144 * <li>{@link CdmAuthority#targetUuid}</li>
145 * </ol>
146 * @param authority
147 * @return an array of tokens
148 * @throws ParsingException
149 */
150 protected String[] parse(String authority) throws ParsingException {
151 //
152 // regex pattern explained:
153 // (\\w*) -> classname
154 // (?:\\((\\w*)\\))? -> (property)
155 // \\.? -> .
156 // (?:(\\w*))(?:\\{([\\da-z\\-]+)\\})? -> Permmission and targetUuid
157 //
158 String regex = "(\\w*)(?:\\((\\w*)\\))?\\.?(?:(\\w*))(?:\\{([\\da-z\\-]+)\\})?";
159 Pattern pattern = Pattern.compile(regex);
160 String[] tokens = new String[4];
161 logger.debug("parsing '" + authority + "'");
162 Matcher m = pattern.matcher(authority);
163
164 if (m.find() && m.groupCount() == 4 ) {
165 for (int i = 0; i < m.groupCount(); i++) {
166 tokens[i] = m.group(i+1);
167 // normalize empty strings to null
168 if(tokens[i] != null && tokens[i].length() == 0){
169 tokens[i] = null;
170 }
171 logger.debug("[" + i + "]: " + tokens[i]+ "\n");
172 }
173 } else {
174 logger.debug("no match");
175 throw new ParsingException("Unsupported authority string: '" + authority + "'");
176 }
177
178 return tokens;
179 }
180
181 /**
182 * {@inheritDoc}
183 *
184 * same as {@link #toString()} and {@link #getAttribute()}
185 */
186 @Override
187 public String getAuthority() {
188 return toString();
189 }
190
191 /**
192 * {@inheritDoc}
193 *
194 * same as {@link #toString()} and {@link #getAuthority()}
195 */
196 @Override
197 public String getAttribute() {
198 return toString();
199 }
200
201 @Override
202 public String toString() {
203 StringBuilder sb = new StringBuilder();
204 sb.append(permissionClass.toString());
205 if(property != null){
206 sb.append('(').append(property).append(')');
207 }
208 sb.append('.').append(operation.toString());
209 if(targetUuid != null){
210 sb.append('{').append(targetUuid.toString()).append('}');
211 }
212 return sb.toString() ;
213 }
214
215 /**
216 * Constructs a new CdmAuthority by parsing the authority string.
217 * For details on the syntax please refer to the class
218 * documentation above.
219 *
220 *
221 * @param authority
222 * @throws ParsingException
223 */
224 public static CdmAuthority fromGrantedAuthority(GrantedAuthority authority) throws ParsingException {
225 return new CdmAuthority(authority.getAuthority());
226 }
227
228 /* (non-Javadoc)
229 * @see eu.etaxonomy.cdm.persistence.hibernate.permission.IGrantedAuthorityConverter#asNewGrantedAuthority()
230 */
231 @Override
232 public GrantedAuthorityImpl asNewGrantedAuthority() throws ParsingException {
233 GrantedAuthorityImpl grantedAuthority = GrantedAuthorityImpl.NewInstance();
234 grantedAuthority.setAuthority(getAuthority());
235 return grantedAuthority;
236 }
237
238
239
240 }