Project

General

Profile

Download (10.5 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.commons.lang3.StringUtils;
19
import org.apache.log4j.Logger;
20
import org.springframework.security.access.ConfigAttribute;
21
import org.springframework.security.core.GrantedAuthority;
22

    
23
import eu.etaxonomy.cdm.model.common.CdmBase;
24
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
25

    
26
/**
27
 * A <code>CdmAuthority</code> consists basically of two parts which are separated
28
 * by a dot character '.'.
29
 *
30
 * <ul>
31
 * <li><code>permissionClass</code>: an {@link CdmPermissionClass} instance with represents a cdm
32
 * type or a part of the cdm type hierarchy. The className is always represented
33
 * as an upper case string.</li>
34
 * <li><code>property</code>: The <code>CdmAuthority</code> only applies to instances
35
 * which satisfy the specified property. Interpretation is up to type specific voters.</li>
36
 * <li><code>operation</code>: A string enclosed in brackets <code>[]</code>
37
 * which specifies one {@link Operation} or
38
 * multiple on that set of cdm types. Multiple {@link Operation} must be comma
39
 * separated.</li>
40
 * <li><code>targetUuid</code>: The <code>operation</code> may be restricted to a specific cdm entity by adding
41
 * the entity uuid to the <code>operation</code>. The uuid string is enclosed in curly brackets '<code>{</code>'
42
 * , '<code>}</code>' and appended to the end of the <code>operation</code>.</li>
43
 * </ul>
44
 *
45
 * <h3>Examples for permissionStrings</h3>
46
 *
47
 * <pre>
48
 * TAXONBASE.[CREATE]
49
 * TAXONBASE.[READ]
50
 * TAXONBASE.[UPDATE]
51
 * TAXONBASE.[DELETE]
52
 * DESCRIPTIONBASE.[UPDATE]
53
 * DESCRIPTIONBASE.[CREATE,UPDATE,DELETE,READ]
54
 * DESCRIPTIONELEMENTBASE(Ecology).[UPDATE]
55
 * TAXONNODE.[UPDATE]{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}
56
 * </pre>
57
 *
58
 * The method {@link #getPermissionString(String)} parses a full authority and returns  permissionString and
59
 * the {@link CdmAuthority} from the <code>authority</code>.
60
 *
61
 *
62
 * @author k.luther
63
 * @author Andreas Kohlbecker
64
 */
65
public class CdmAuthority implements GrantedAuthority, ConfigAttribute, IGrantedAuthorityConverter {
66

    
67
    private static final long serialVersionUID = 1L;
68

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

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

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

    
81
    public CdmAuthority(CdmBase targetDomainObject, EnumSet<CRUD> operation){
82

    
83
        this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);
84
        this.property = null;
85
        if(operation != null) {
86
        	this.operation = operation;
87
        }
88
        if(targetDomainObject.getUuid() == null){
89
            throw new NullPointerException("UUID of targetDomainObject is null. CDM entities need to be saved prior using this function");
90
        }
91
        this.targetUuid = targetDomainObject.getUuid();
92
    }
93

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

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

    
112

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

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

    
129
    protected CdmAuthority (String authority) throws CdmAuthorityParsingException{
130

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

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

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

    
154
    public CdmPermissionClass getPermissionClass(){
155
        return permissionClass;
156
    }
157

    
158
    public String getProperty(){
159
        return property;
160
    }
161

    
162
    public EnumSet<CRUD> getOperation(){
163
        return operation;
164
    }
165

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

    
170
    public UUID getTargetUUID(){
171
        return targetUuid;
172
    }
173

    
174
    public boolean hasTargetUuid() {
175
        return targetUuid != null;
176
    }
177

    
178
    public boolean hasProperty() {
179
        return property != null;
180
    }
181

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

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

    
224
        return tokens;
225
    }
226

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

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

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

    
261
    /**
262
     * @return
263
     */
264
    protected String operationsToString() {
265
        String[] opsstr = new String[operation.size()];
266
        int i = 0;
267
        for(CRUD crud : operation){
268
            opsstr[i++] = crud.name();
269
        }
270
        String asString = StringUtils.join(opsstr, ",");
271
        return "[" + asString + "]";
272
    }
273

    
274
    /**
275
     * Constructs a new CdmAuthority by parsing the authority string.
276
     * For details on the syntax please refer to the class
277
     * documentation above.
278
     * <p>
279
     * This method is mainly used by the permission voters ({@link CdmPermissionVoter)}.
280
     * In order to improve the voting process this method is caching the <code>CdmAuthority</code>
281
     * instances per <code>GrantedAuthority</code> string in a map.
282
     *
283
     * @param authority
284
     * @throws CdmAuthorityParsingException
285
     */
286
    public static CdmAuthority fromGrantedAuthority(GrantedAuthority authority) throws CdmAuthorityParsingException {
287
        CdmAuthority cdmAuthority = grantedAuthorityCache.get(authority.getAuthority());
288
        if(cdmAuthority == null){
289
            cdmAuthority = new CdmAuthority(authority.getAuthority());
290
        }
291
        return cdmAuthority;
292
//        return  new CdmAuthority(authority.getAuthority());
293
    }
294

    
295

    
296
    @Override
297
    public GrantedAuthorityImpl asNewGrantedAuthority() throws CdmAuthorityParsingException {
298
        GrantedAuthorityImpl grantedAuthority = GrantedAuthorityImpl.NewInstance(getAuthority());
299
        return grantedAuthority;
300
    }
301

    
302

    
303
}
(2-2/10)