This project has retired. For details please refer to its Attic page.
DefaultRoleTemplateProcessor xref
View Javadoc

1   package org.apache.archiva.redback.role.template;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.archiva.redback.rbac.Operation;
23  import org.apache.archiva.redback.rbac.Permission;
24  import org.apache.archiva.redback.rbac.RbacManagerException;
25  import org.apache.archiva.redback.rbac.Resource;
26  import org.apache.archiva.redback.rbac.Role;
27  import org.apache.archiva.redback.rbac.RBACManager;
28  import org.apache.archiva.redback.role.RoleManagerException;
29  import org.apache.archiva.redback.role.model.ModelApplication;
30  import org.apache.archiva.redback.role.model.ModelOperation;
31  import org.apache.archiva.redback.role.model.ModelPermission;
32  import org.apache.archiva.redback.role.model.ModelResource;
33  import org.apache.archiva.redback.role.model.ModelRole;
34  import org.apache.archiva.redback.role.model.ModelTemplate;
35  import org.apache.archiva.redback.role.model.RedbackRoleModel;
36  import org.apache.archiva.redback.role.util.RoleModelUtils;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.springframework.stereotype.Service;
40  
41  import javax.inject.Inject;
42  import javax.inject.Named;
43  import java.util.ArrayList;
44  import java.util.Collections;
45  import java.util.Iterator;
46  import java.util.List;
47  
48  /**
49   * DefaultRoleTemplateProcessor: inserts the components of a template into the rbac manager
50   *
51   * @author: Jesse McConnell <jesse@codehaus.org>
52   */
53  @Service("roleTemplateProcessor")
54  public class DefaultRoleTemplateProcessor
55      implements RoleTemplateProcessor
56  {
57      private Logger log = LoggerFactory.getLogger( DefaultRoleTemplateProcessor.class );
58  
59      @Inject
60      @Named(value = "rbacManager#default")
61      private RBACManager rbacManager;
62  
63      @SuppressWarnings("unchecked")
64      public void create( RedbackRoleModel model, String templateId, String resource )
65          throws RoleManagerException
66      {
67          for ( ModelApplication application : model.getApplications() )
68          {
69              for ( ModelTemplate template : application.getTemplates() )
70              {
71                  if ( templateId.equals( template.getId() ) )
72                  {
73                      // resource can be special
74                      processResource( template, resource );
75  
76                      // templates are roles that have yet to be paired with a resource for creation
77                      processTemplate( model, template, resource );
78  
79                      return;
80                  }
81              }
82          }
83  
84          throw new RoleManagerException( "unknown template '" + templateId + "'" );
85      }
86  
87      @SuppressWarnings("unchecked")
88      public void remove( RedbackRoleModel model, String templateId, String resource )
89          throws RoleManagerException
90      {
91          for ( ModelApplication application : model.getApplications() )
92          {
93              for ( ModelTemplate template : application.getTemplates() )
94              {
95                  if ( templateId.equals( template.getId() ) )
96                  {
97                      removeTemplatedRole( model, template, resource );
98                      return;
99                  }
100             }
101         }
102 
103         throw new RoleManagerException( "unknown template '" + templateId + "'" );
104     }
105 
106     private void removeTemplatedRole( RedbackRoleModel model, ModelTemplate template, String resource )
107         throws RoleManagerException
108     {
109         String roleName = template.getNamePrefix() + template.getDelimiter() + resource;
110 
111         try
112         {
113             Role role = rbacManager.getRole( roleName );
114 
115             if ( !role.isPermanent() )
116             {
117                 // remove the role
118                 rbacManager.removeRole( role );
119 
120                 // remove the permissions
121                 // todo, do this in a better way too, permissions can be shared across multiple roles and that could blow chunks here.
122                 //for ( Iterator i = template.getPermissions().iterator(); i.hasNext(); )
123                 //{
124                 //    ModelPermission permission = (ModelPermission) i.next();
125                 //    if ( !permission.isPermanent() )
126                 //    {                                                                        
127                 //            rbacManager.removePermission( permission.getName() + template.getDelimiter()
128                 //                       + resolvePermissionResource( model, permission, resolvePermissionResource( model, permission, resource ) ) );                     
129                 //   }
130                 //}
131 
132                 // check if we want to remove the resources
133                 Resource rbacResource = rbacManager.getResource( resource );
134 
135                 if ( !rbacResource.isPermanent() )
136                 {
137                     //todo we need a better way of finding if a resource is unused anymore...probably a cleaning process in the db or something
138                     //rbacManager.removeResource( rbacResource );
139                 }
140 
141                 // todo find dangling child role references and smoke
142             }
143             else
144             {
145                 throw new RoleManagerException( "unable to remove role, it is flagged permanent" );
146             }
147         }
148         catch ( RbacManagerException e )
149         {
150             throw new RoleManagerException( "unable to remove templated role: " + roleName, e );
151         }
152         //catch ( RoleTemplateProcessorException e )
153         //{
154         //    throw new RoleManagerException( "unable to remove templated role, error resolving resource: Role:" + roleName + " Resource: " + resource, e );
155         //}
156     }
157 
158     private void processResource( ModelTemplate template, String resource )
159         throws RoleManagerException
160     {
161         if ( !rbacManager.resourceExists( resource ) )
162         {
163             try
164             {
165                 Resource res = rbacManager.createResource( resource );
166                 res.setPermanent( template.isPermanentResource() );
167                 rbacManager.saveResource( res );
168             }
169             catch ( RbacManagerException e )
170             {
171                 throw new RoleManagerException( "error creating resource '" + resource + "'", e );
172             }
173         }
174     }
175 
176     @SuppressWarnings("unchecked")
177     private void processTemplate( RedbackRoleModel model, ModelTemplate template, String resource )
178         throws RoleManagerException
179     {
180         String templateName = template.getNamePrefix() + template.getDelimiter() + resource;
181 
182         List<Permission> permissions = processPermissions( model, template, resource );
183 
184         boolean roleExists = false;
185 
186         try
187         {
188             roleExists = rbacManager.roleExists( templateName );
189         }
190         catch ( RbacManagerException e )
191         {
192             throw new RoleManagerException( e.getMessage(), e );
193         }
194 
195         if ( !roleExists )
196         {
197             try
198             {
199                 Role role = rbacManager.createRole( templateName );
200                 role.setDescription( template.getDescription() );
201                 role.setPermanent( template.isPermanent() );
202                 role.setAssignable( template.isAssignable() );
203 
204                 // add any permissions associated with this role
205                 for ( Iterator<Permission> j = permissions.iterator(); j.hasNext(); )
206                 {
207                     Permission permission = j.next();
208 
209                     role.addPermission( permission );
210                 }
211 
212                 // add child roles to this role
213                 if ( template.getChildRoles() != null )
214                 {
215                     for ( String childRoleId : template.getChildRoles() )
216                     {
217                         ModelRole childRoleProfile = RoleModelUtils.getModelRole( model, childRoleId );
218                         role.addChildRoleName( childRoleProfile.getName() );
219                     }
220                 }
221 
222                 // add child templates to this role, be nice and make them if they don't exist
223                 if ( template.getChildTemplates() != null )
224                 {
225                     for ( String childTemplateId : template.getChildTemplates() )
226                     {
227                         ModelTemplate childModelTemplate = RoleModelUtils.getModelTemplate( model, childTemplateId );
228 
229                         if ( childModelTemplate == null )
230                         {
231                             throw new RoleManagerException(
232                                 "error obtaining child template from model: template " + templateName
233                                     + " # child template: " + childTemplateId );
234                         }
235 
236                         String childRoleName =
237                             childModelTemplate.getNamePrefix() + childModelTemplate.getDelimiter() + resource;
238 
239                         // check if the role exists, if it does then add it as a child, otherwise make it and add it
240                         // this should be safe since validation should protect us from template cycles
241                         if ( rbacManager.roleExists( childRoleName ) )
242                         {
243                             role.addChildRoleName( childRoleName );
244                         }
245                         else
246                         {
247                             processTemplate( model, childModelTemplate, resource );
248 
249                             role.addChildRoleName( childRoleName );
250                         }
251                     }
252                 }
253 
254                 // this role needs to be saved since it now needs to be added as a child role by 
255                 // another role
256                 if ( !rbacManager.roleExists( role.getName() ) )
257                 {
258                     role = rbacManager.saveRole( role );
259                 }
260 
261                 // add link from parent roles to this new role
262                 if ( template.getParentRoles() != null )
263                 {
264                     for ( String parentRoleId : template.getParentRoles() )
265                     {
266                         ModelRole parentModelRole = RoleModelUtils.getModelRole( model, parentRoleId );
267                         Role parentRole = rbacManager.getRole( parentModelRole.getName() );
268                         parentRole.addChildRoleName( role.getName() );
269                         rbacManager.saveRole( parentRole );
270                     }
271                 }
272 
273                 // add child templates to this role, be nice and make them if they don't exist
274                 if ( template.getParentTemplates() != null )
275                 {
276                     for ( String parentTemplateId : template.getParentTemplates() )
277                     {
278                         ModelTemplate parentModelTemplate = RoleModelUtils.getModelTemplate( model, parentTemplateId );
279 
280                         if ( parentModelTemplate == null )
281                         {
282                             throw new RoleManagerException(
283                                 "error obtaining parent template from model: template " + templateName
284                                     + " # child template: " + parentTemplateId );
285                         }
286 
287                         String parentRoleName =
288                             parentModelTemplate.getNamePrefix() + parentModelTemplate.getDelimiter() + resource;
289 
290                         // check if the role exists, if it does then add it as a child, otherwise make it and add it
291                         // this should be safe since validation should protect us from template cycles
292                         if ( rbacManager.roleExists( parentRoleName ) )
293                         {
294                             Role parentRole = rbacManager.getRole( parentRoleName );
295 
296                             parentRole.addChildRoleName( role.getName() );
297                             rbacManager.saveRole( parentRole );
298                         }
299                         else
300                         {
301                             processTemplate( model, parentModelTemplate, resource );
302 
303                             Role parentRole = rbacManager.getRole( parentRoleName );
304 
305                             parentRole.addChildRoleName( role.getName() );
306                             rbacManager.saveRole( parentRole );
307                         }
308                     }
309                 }
310 
311             }
312             catch ( RbacManagerException e )
313             {
314                 throw new RoleManagerException( "error creating role '" + templateName + "'", e );
315             }
316         }
317         else
318         {
319             try
320             {
321                 Role role = rbacManager.getRole( templateName );
322 
323                 boolean changed = false;
324                 for ( Permission permission : permissions )
325                 {
326                     if ( !role.getPermissions().contains( permission ) )
327                     {
328                         log.info(
329                             "Adding new permission '" + permission.getName() + "' to role '" + role.getName() + "'" );
330                         role.addPermission( permission );
331                         changed = true;
332                     }
333                 }
334 
335                 // Copy list to avoid concurrent modifications
336                 List<Permission> oldPermissions = new ArrayList<Permission>( role.getPermissions() );
337                 for ( Permission permission : oldPermissions )
338                 {
339                     if ( !permissions.contains( permission ) )
340                     {
341                         log.info( "Removing old permission '{}' from role '{}'", permission.getName(), role.getName() );
342                         role.removePermission( permission );
343                         changed = true;
344                     }
345                 }
346                 if ( changed )
347                 {
348                     rbacManager.saveRole( role );
349                 }
350             }
351             catch ( RbacManagerException e )
352             {
353                 throw new RoleManagerException( "error updating role '" + templateName + "'", e );
354             }
355         }
356     }
357 
358     @SuppressWarnings("unchecked")
359     private List<Permission> processPermissions( RedbackRoleModel model, ModelTemplate template, String resource )
360         throws RoleManagerException
361     {
362 
363         if ( template.getPermissions() != null )
364         {
365             // copy list to avoid concurrent modifications
366             List<ModelPermission> templatePermissions = new ArrayList<ModelPermission>( template.getPermissions() );
367             List<Permission> rbacPermissions = new ArrayList<Permission>( templatePermissions.size() );
368             for ( ModelPermission profilePermission : templatePermissions )
369             {
370                 try
371                 {
372                     String permissionName =
373                         profilePermission.getName() + template.getDelimiter() + resolvePermissionResource( model,
374                                                                                                            profilePermission,
375                                                                                                            resource );
376 
377                     if ( !rbacManager.permissionExists( permissionName ) )
378                     {
379 
380                         Permission permission = rbacManager.createPermission( permissionName );
381 
382                         ModelOperation modelOperation =
383                             RoleModelUtils.getModelOperation( model, profilePermission.getOperation() );
384                         Operation rbacOperation = rbacManager.getOperation( modelOperation.getName() );
385 
386                         String permissionResource = resolvePermissionResource( model, profilePermission, resource );
387 
388                         Resource rbacResource = rbacManager.getResource( permissionResource );
389 
390                         permission.setOperation( rbacOperation );
391                         permission.setResource( rbacResource );
392                         permission.setPermanent( profilePermission.isPermanent() );
393                         permission.setDescription( profilePermission.getDescription() );
394 
395                         permission = rbacManager.savePermission( permission );
396 
397                         rbacPermissions.add( permission );
398 
399                     }
400                     else
401                     {
402 
403                         rbacPermissions.add( rbacManager.getPermission( permissionName ) );
404 
405                     }
406                 }
407                 catch ( RbacManagerException e )
408                 {
409                     throw new RoleManagerException( "unable to generate templated role: " + e.getMessage(), e );
410                 }
411                 catch ( RoleTemplateProcessorException e )
412                 {
413                     throw new RoleManagerException( "unable to resolve resource: " + resource, e );
414                 }
415             }
416             return rbacPermissions;
417         }
418 
419         return Collections.emptyList();
420     }
421 
422     private String resolvePermissionResource( RedbackRoleModel model, ModelPermission permission, String resource )
423         throws RoleTemplateProcessorException
424     {
425         String permissionResource = permission.getResource();
426 
427         // if permission's resource is ${resource}, return the resource passed in
428         if ( permissionResource.startsWith( "${" ) )
429         {
430             String tempStr = permissionResource.substring( 2, permissionResource.indexOf( '}' ) );
431 
432             if ( "resource".equals( tempStr ) )
433             {
434                 return resource;
435             }
436         }
437 
438         // check if the resource resolves to declared operation
439         String declaredResource = resolveResource( model, permission.getResource() );
440         if ( declaredResource != null )
441         {
442             return declaredResource;
443         }
444         else
445         {
446             // either niether of the above apply, then its the resource.
447             return resource;
448         }
449     }
450 
451     private String resolveResource( RedbackRoleModel model, String resource )
452         throws RoleTemplateProcessorException
453     {
454         ModelResource resolvedResource = RoleModelUtils.getModelResource( model, resource );
455 
456         if ( resolvedResource != null )
457         {
458             return resolvedResource.getName();
459         }
460         else
461         {
462             return null;
463         }
464     }
465 
466     public RBACManager getRbacManager()
467     {
468         return rbacManager;
469     }
470 
471     public void setRbacManager( RBACManager rbacManager )
472     {
473         this.rbacManager = rbacManager;
474     }
475 }