001package org.apache.archiva.redback.role.processor;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.archiva.redback.rbac.Operation;
023import org.apache.archiva.redback.rbac.Permission;
024import org.apache.archiva.redback.rbac.RBACManager;
025import org.apache.archiva.redback.rbac.RbacManagerException;
026import org.apache.archiva.redback.rbac.Resource;
027import org.apache.archiva.redback.rbac.Role;
028import org.apache.archiva.redback.role.RoleManagerException;
029import org.apache.archiva.redback.role.model.ModelApplication;
030import org.apache.archiva.redback.role.model.ModelOperation;
031import org.apache.archiva.redback.role.model.ModelPermission;
032import org.apache.archiva.redback.role.model.ModelResource;
033import org.apache.archiva.redback.role.model.ModelRole;
034import org.apache.archiva.redback.role.model.RedbackRoleModel;
035import org.apache.archiva.redback.role.util.RoleModelUtils;
036import org.apache.commons.lang3.time.StopWatch;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import org.springframework.stereotype.Service;
040
041import javax.inject.Inject;
042import javax.inject.Named;
043import java.util.ArrayList;
044import java.util.HashMap;
045import java.util.HashSet;
046import java.util.List;
047import java.util.Map;
048import java.util.Set;
049
050/**
051 * DefaultRoleModelProcessor: inserts the components of the model that can be populated into the rbac manager
052 *
053 * @author: Jesse McConnell
054 */
055@Service( "roleModelProcessor" )
056public class DefaultRoleModelProcessor
057    implements RoleModelProcessor
058{
059    private Logger log = LoggerFactory.getLogger( DefaultRoleModelProcessor.class );
060
061    @Inject
062    @Named( value = "rbacManager#default" )
063    private RBACManager rbacManager;
064
065    private Map<String, Resource> resourceMap = new HashMap<String, Resource>();
066
067    private Map<String, Operation> operationMap = new HashMap<String, Operation>();
068
069    public void process( RedbackRoleModel model )
070        throws RoleManagerException
071    {
072        // must process resources and operations first, they are required for the
073        // permissions in the roles to add in correctly
074        processResources( model );
075        processOperations( model );
076
077        processRoles( model );
078    }
079
080    @SuppressWarnings( "unchecked" )
081    private void processResources( RedbackRoleModel model )
082        throws RoleManagerException
083    {
084        for ( ModelApplication application : model.getApplications() )
085        {
086            for ( ModelResource profileResource : application.getResources() )
087            {
088                try
089                {
090                    if ( !rbacManager.resourceExists( profileResource.getName() ) )
091                    {
092
093                        Resource resource = rbacManager.createResource( profileResource.getName() );
094                        resource.setPermanent( profileResource.isPermanent() );
095                        resource = rbacManager.saveResource( resource );
096
097                        // store for use in permission creation
098                        resourceMap.put( profileResource.getId(), resource );
099
100                    }
101                    else
102                    {
103                        resourceMap.put( profileResource.getId(),
104                                         rbacManager.getResource( profileResource.getName() ) );
105                    }
106                }
107                catch ( RbacManagerException e )
108                {
109                    throw new RoleManagerException( "error creating resource '" + profileResource.getName() + "'", e );
110                }
111            }
112        }
113    }
114
115    @SuppressWarnings( "unchecked" )
116    private void processOperations( RedbackRoleModel model )
117        throws RoleManagerException
118    {
119        for ( ModelApplication application : model.getApplications() )
120        {
121            for ( ModelOperation profileOperation : application.getOperations() )
122            {
123                try
124                {
125                    if ( !rbacManager.operationExists( profileOperation.getName() ) )
126                    {
127
128                        Operation operation = rbacManager.createOperation( profileOperation.getName() );
129                        operation.setPermanent( profileOperation.isPermanent() );
130                        operation.setDescription( profileOperation.getDescription() );
131                        operation = rbacManager.saveOperation( operation );
132
133                        // store for use in permission creation
134                        operationMap.put( profileOperation.getId(), operation );
135
136                    }
137                    else
138                    {
139                        operationMap.put( profileOperation.getId(),
140                                          rbacManager.getOperation( profileOperation.getName() ) );
141                    }
142                }
143                catch ( RbacManagerException e )
144                {
145                    throw new RoleManagerException( "error creating operation '" + profileOperation.getName() + "'",
146                                                    e );
147                }
148            }
149        }
150    }
151
152    @SuppressWarnings( "unchecked" )
153    private void processRoles( RedbackRoleModel model )
154        throws RoleManagerException
155    {
156        StopWatch stopWatch = new StopWatch();
157        stopWatch.reset();
158        stopWatch.start();
159        List<String> sortedGraph = RoleModelUtils.reverseTopologicalSortedRoleList(model);
160
161        List<? extends Role> allRoles;
162        try
163        {
164            allRoles = rbacManager.getAllRoles();
165        }
166        catch ( RbacManagerException e )
167        {
168            throw new RoleManagerException( e.getMessage(), e );
169        }
170
171        Set<String> allRoleNames = new HashSet<String>( allRoles.size() );
172        for ( Role role : allRoles )
173        {
174            allRoleNames.add( role.getName() );
175        }
176
177        for ( String roleId : sortedGraph )
178        {
179            ModelRole roleProfile = RoleModelUtils.getModelRole( model, roleId );
180
181            List<? extends Permission> permissions = processPermissions( roleProfile.getPermissions() );
182
183            boolean roleExists = allRoleNames.contains( roleProfile.getName() );// false;
184
185            /*try
186            {
187                roleExists = rbacManager.roleExists( roleProfile.getName() );
188            }
189            catch ( RbacManagerException e )
190            {
191                throw new RoleManagerException( e.getMessage(), e );
192            }*/
193
194            if ( !roleExists )
195            {
196                try
197                {
198                    Role role = rbacManager.createRole( roleProfile.getName() );
199                    role.setId( roleProfile.getId() );
200                    role.setModelId( roleProfile.getId() );
201                    role.setTemplateInstance( false );
202                    role.setDescription( roleProfile.getDescription() );
203                    role.setPermanent( roleProfile.isPermanent() );
204                    role.setAssignable( roleProfile.isAssignable() );
205
206                    // add any permissions associated with this role
207                    for ( Permission permission : permissions )
208                    {
209                        role.addPermission( permission );
210                    }
211
212                    // add child roles to this role
213                    if ( roleProfile.getChildRoles() != null )
214                    {
215                        for ( String childRoleId : roleProfile.getChildRoles() )
216                        {
217                            ModelRole childRoleProfile = RoleModelUtils.getModelRole( model, childRoleId );
218                            role.addChildRoleName( childRoleProfile.getName() );
219                            role.addChildRoleId( childRoleProfile.getId() );
220                        }
221                    }
222
223                    rbacManager.saveRole( role );
224                    allRoleNames.add( role.getName() );
225
226                    // add link from parent roles to this new role
227                    if ( roleProfile.getParentRoles() != null )
228                    {
229                        for ( String parentRoleId : roleProfile.getParentRoles() )
230                        {
231                            ModelRole parentModelRole = RoleModelUtils.getModelRole( model, parentRoleId );
232                            Role parentRole = rbacManager.getRole( parentModelRole.getName() );
233                            parentRole.addChildRole( role );
234                            rbacManager.saveRole( parentRole );
235                            allRoleNames.add( parentRole.getName() );
236                        }
237                    }
238
239                }
240                catch ( RbacManagerException e )
241                {
242                    throw new RoleManagerException( "error creating role '" + roleProfile.getName() + "'", e );
243                }
244            }
245            else
246            {
247                try
248                {
249                    Role role = rbacManager.getRole( roleProfile.getName() );
250
251                    boolean changed = false;
252                    for ( Permission permission : permissions )
253                    {
254                        if ( !role.getPermissions().contains( permission ) )
255                        {
256                            log.info( "Adding new permission '{}' to role '{}'", permission.getName(), role.getName() );
257                            role.addPermission( permission );
258                            changed = true;
259                        }
260                    }
261
262                    // Copy list to avoid concurrent modification [REDBACK-220]
263                    List<Permission> oldPermissions = new ArrayList<Permission>( role.getPermissions() );
264                    for ( Permission permission : oldPermissions )
265                    {
266                        if ( !permissions.contains( permission ) )
267                        {
268                            log.info(
269                                "Removing old permission '{}' from role '{}'", permission.getName(), role.getName() );
270                            role.removePermission( permission );
271                            changed = true;
272                        }
273                    }
274                    if ( changed )
275                    {
276                        rbacManager.saveRole( role );
277                        allRoleNames.add( role.getName() );
278                    }
279                }
280                catch ( RbacManagerException e )
281                {
282                    throw new RoleManagerException( "error updating role '" + roleProfile.getName() + "'", e );
283                }
284            }
285        }
286        stopWatch.stop();
287        log.info( "time to process roles model: {} ms", stopWatch.getTime() );
288    }
289
290    private List<? extends Permission> processPermissions( List<ModelPermission> permissions )
291        throws RoleManagerException
292    {
293        List<Permission> rbacPermissions = new ArrayList<Permission>( permissions.size() );
294
295        for ( ModelPermission profilePermission : permissions )
296        {
297            try
298            {
299                if ( !rbacManager.permissionExists( profilePermission.getName() ) )
300                {
301
302                    Permission permission = rbacManager.createPermission( profilePermission.getName() );
303
304                    // get the operation out of the map we stored it in when we created it _by_ the id in the model
305                    Operation operation = (Operation) operationMap.get( profilePermission.getOperation() );
306                    // same with resource
307                    Resource resource = (Resource) resourceMap.get( profilePermission.getResource() );
308
309                    permission.setOperation( operation );
310                    permission.setResource( resource );
311                    permission.setPermanent( profilePermission.isPermanent() );
312                    permission.setDescription( profilePermission.getDescription() );
313
314                    permission = rbacManager.savePermission( permission );
315
316                    rbacPermissions.add( permission );
317
318                }
319                else
320                {
321                    rbacPermissions.add( rbacManager.getPermission( profilePermission.getName() ) );
322                }
323            }
324            catch ( RbacManagerException e )
325            {
326                throw new RoleManagerException( "error creating permission '" + profilePermission.getName() + "'", e );
327            }
328        }
329        return rbacPermissions;
330    }
331
332    public RBACManager getRbacManager()
333    {
334        return rbacManager;
335    }
336
337    public void setRbacManager( RBACManager rbacManager )
338    {
339        this.rbacManager = rbacManager;
340    }
341}
342
343