Project

General

Profile

Download (10.1 KB) Statistics
| Branch: | Tag: | Revision:
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.HashMap;
13
import java.util.Map;
14
import java.util.UUID;
15
import java.util.regex.Matcher;
16
import java.util.regex.Pattern;
17

    
18
import org.apache.log4j.Logger;
19
import org.springframework.security.access.ConfigAttribute;
20
import org.springframework.security.core.GrantedAuthority;
21

    
22
import eu.etaxonomy.cdm.model.common.CdmBase;
23
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
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 enclosed in brackets <code>[]</code>
36
 * which specifies one {@link Operation} or
37
 * multiple on that set of cdm types. Multiple {@link Operation} must be comma
38
 * separated.</li>
39
 * <li><code>targetUuid</code>: The <code>operation</code> may be restricted to a specific cdm entity by adding
40
 * the entity uuid to the <code>operation</code>. The uuid string is enclosed in curly brackets '<code>{</code>'
41
 * , '<code>}</code>' and appended to the end of the <code>operation</code>.</li>
42
 * </ul>
43
 *
44
 * <h3>Examples for permissionStrings</h3>
45
 *
46
 * <pre>
47
 * TAXONBASE.[CREATE]
48
 * TAXONBASE.[READ]
49
 * TAXONBASE.[UPDATE]
50
 * TAXONBASE.[DELETE]
51
 * DESCRIPTIONBASE.[UPDATE]
52
 * DESCRIPTIONBASE.[CREATE,UPDATE,DELETE,READ]
53
 * DESCRIPTIONELEMENTBASE(Ecology).[UPDATE]
54
 * TAXONNODE.[UPDATE]{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}
55
 * </pre>
56
 *
57
 * The method {@link #getPermissionString(String)} parses a full authority and returns  permissionString and
58
 * the {@link CdmAuthority} from the <code>authority</code>.
59
 *
60
 *
61
 * @author k.luther
62
 * @author Andreas Kohlbecker
63
 */
64
public class CdmAuthority implements GrantedAuthority, ConfigAttribute, IGrantedAuthorityConverter {
65

    
66
    private static final long serialVersionUID = 1L;
67

    
68
    public static final Logger logger = Logger.getLogger(CdmAuthority.class);
69

    
70
    private static Map<String, CdmAuthority> grantedAuthorityCache = new HashMap<String, CdmAuthority>();
71

    
72
    CdmPermissionClass permissionClass;
73
    String property;
74
    // Making sure that operation is always initialized, for both
75
    // - the string representation to have a '[]'
76
    // - and the object representation to never be null (with check in constructors)
77
    EnumSet<CRUD> operation = EnumSet.noneOf(CRUD.class);
78
    UUID targetUuid;
79

    
80
    public CdmAuthority(CdmBase targetDomainObject, EnumSet<CRUD> operation){
81
        this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);
82
        this.property = null;
83
        if(operation != null) {
84
        	this.operation = operation;
85
        }
86
        if(targetDomainObject.getUuid() == null){
87
            throw new NullPointerException("UUID of targetDomainObject is null. CDM entities need to be saved prior using this function");
88
        }
89
        this.targetUuid = targetDomainObject.getUuid();
90
    }
91

    
92
     public CdmAuthority(CdmBase targetDomainObject, String property, EnumSet<CRUD> operation, UUID uuid){
93
       this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);
94
        this.property = property;
95
        if(operation != null) {
96
        	this.operation = operation;
97
        }
98
        this.targetUuid = uuid;
99
    }
100

    
101
     public CdmAuthority(Class<? extends CdmBase> targetDomainType, String property, EnumSet<CRUD> operation, UUID uuid){
102
         this.permissionClass = CdmPermissionClass.getValueOf(targetDomainType);
103
          this.property = property;
104
          if(operation != null) {
105
              this.operation = operation;
106
          }
107
          this.targetUuid = uuid;
108
      }
109

    
110

    
111
    public CdmAuthority(CdmPermissionClass permissionClass, String property, EnumSet<CRUD> operation, UUID uuid){
112
        this.permissionClass = permissionClass;
113
        this.property = property;
114
        if(operation != null) {
115
        	this.operation = operation;
116
        }
117
        this.targetUuid = uuid;
118
    }
119

    
120
    public CdmAuthority(CdmPermissionClass permissionClass, EnumSet<CRUD> operation){
121
        this.permissionClass = permissionClass;
122
        if(operation != null) {
123
            this.operation = operation;
124
        }
125
    }
126

    
127
    private CdmAuthority (String authority) throws CdmAuthorityParsingException{
128

    
129
        String[] tokens = parse(authority);
130
        // className must never be null
131

    
132
        try {
133
            permissionClass = CdmPermissionClass.valueOf(tokens[0]);
134
        } catch (IllegalArgumentException e) {
135
            throw new CdmAuthorityParsingException(authority);
136
        }
137
        property = tokens[1];
138

    
139
        if(tokens[2] != null){
140
            try {
141
                operation = Operation.fromString(tokens[2]);
142
            } catch (IllegalArgumentException e) {
143
                logger.warn("cannot parse Operation " + tokens[2]);
144
                throw new CdmAuthorityParsingException(authority);
145
            }
146
        }
147
        if(tokens[3] != null){
148
            targetUuid = UUID.fromString(tokens[3]);
149
        }
150
    }
151

    
152
    public CdmPermissionClass getPermissionClass(){
153
        return permissionClass;
154
    }
155

    
156
    public String getProperty(){
157
        return property;
158
    }
159

    
160
    public EnumSet<CRUD> getOperation(){
161
        return operation;
162
    }
163

    
164
    public void setOperation(EnumSet<CRUD> operation) {
165
        this.operation = operation;
166
    }
167

    
168
    public UUID getTargetUUID(){
169
        return targetUuid;
170
    }
171

    
172
    public boolean hasTargetUuid() {
173
        return targetUuid != null;
174
    }
175

    
176
    public boolean hasProperty() {
177
        return property != null;
178
    }
179

    
180
    /**
181
     * Parses the given <code>authority</code> and returns an array of tokens.
182
     * The array has a length of four elements whereas the elements can be null.
183
     * The elements in the array correspond to the fields of {@link CdmAuthority}:
184
     * <ol>
185
     * <li>{@link CdmAuthority#permissionClass}</li>
186
     * <li>{@link CdmAuthority#property}</li>
187
     * <li>{@link CdmAuthority#operation}</li>
188
     * <li>{@link CdmAuthority#targetUuid}</li>
189
     * </ol>
190
     * @param authority
191
     * @return an array of tokens
192
     * @throws CdmAuthorityParsingException
193
     */
194
    protected String[] parse(String authority) throws CdmAuthorityParsingException {
195
        //
196
        // regex pattern explained:
197
        //  (\\w*)             -> classname
198
        //  (?:\\((\\w*)\\))?  -> (property)
199
        //  \\.?               -> .
200
        //  (?:\\[(\\D*)\\])(?:\\{([\\da-z\\-]+)\\})? -> Permission and targetUuid
201
        //
202
        String regex = "(\\w*)(?:\\((\\w*)\\))?\\.?(?:\\[(\\D*)\\])?(?:\\{([\\da-z\\-]+)\\})?";
203
        Pattern pattern = Pattern.compile(regex);
204
        String[] tokens = new String[4];
205
        logger.debug("parsing '" + authority + "'");
206
        Matcher m = pattern.matcher(authority);
207

    
208
        if (m.find() && m.groupCount() == 4 ) {
209
            for (int i = 0; i < m.groupCount(); i++) {
210
                tokens[i] = m.group(i+1);
211
                // normalize empty strings to null
212
                if(tokens[i] != null && tokens[i].length() == 0){
213
                    tokens[i] = null;
214
                }
215
                logger.trace("[" + i + "]: " + tokens[i]+ "\n");
216
            }
217
        } else {
218
            logger.debug("no match");
219
            throw new CdmAuthorityParsingException("Unsupported authority string: '" + authority + "'");
220
        }
221

    
222
        return tokens;
223
    }
224

    
225
    /**
226
     * {@inheritDoc}
227
     *
228
     * same as {@link #toString()} and  {@link #getAttribute()}
229
     */
230
    @Override
231
    public String getAuthority() {
232
        return toString();
233
    }
234

    
235
    /**
236
     * {@inheritDoc}
237
     *
238
     * same as {@link #toString()} and  {@link #getAuthority()}
239
     */
240
    @Override
241
    public String getAttribute() {
242
        return toString();
243
    }
244

    
245
    @Override
246
    public String toString() {
247
        StringBuilder sb = new StringBuilder();
248
        sb.append(permissionClass.toString());
249
        if(property != null){
250
            sb.append('(').append(property).append(')');
251
        }
252
        sb.append('.').append(operation.toString());
253
        if(targetUuid != null){
254
            sb.append('{').append(targetUuid.toString()).append('}');
255
        }
256
        return sb.toString() ;
257
    }
258

    
259
    /**
260
     * Constructs a new CdmAuthority by parsing the authority string.
261
     * For details on the syntax please refer to the class
262
     * documentation above.
263
     * <p>
264
     * This method is mainly used by the permission voters ({@link CdmPermissionVoter)}.
265
     * In order to improve the voting process this method is caching the <code>CdmAuthority</code>
266
     * instances per <code>GrantedAuthority</code> string in a map.
267
     *
268
     * @param authority
269
     * @throws CdmAuthorityParsingException
270
     */
271
    public static CdmAuthority fromGrantedAuthority(GrantedAuthority authority) throws CdmAuthorityParsingException {
272
        CdmAuthority cdmAuthority = grantedAuthorityCache.get(authority.getAuthority());
273
        if(cdmAuthority == null){
274
            cdmAuthority = new CdmAuthority(authority.getAuthority());
275
        }
276
        return cdmAuthority;
277
//        return  new CdmAuthority(authority.getAuthority());
278
    }
279

    
280

    
281
    @Override
282
    public GrantedAuthorityImpl asNewGrantedAuthority() throws CdmAuthorityParsingException {
283
        GrantedAuthorityImpl grantedAuthority = GrantedAuthorityImpl.NewInstance(getAuthority());
284
        return grantedAuthority;
285
    }
286

    
287

    
288
}
(2-2/10)