blob: d7969b2d1f68c51be9ab3b7867eda9568fe97a4e [file] [log] [blame]
package org.apache.archiva.redback.rbac.ldap;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.redback.common.ldap.MappingException;
import org.apache.archiva.redback.common.ldap.connection.LdapConnection;
import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
import org.apache.archiva.redback.common.ldap.connection.LdapException;
import org.apache.archiva.redback.common.ldap.role.LdapRoleMapper;
import org.apache.archiva.redback.common.ldap.role.LdapRoleMapperConfiguration;
import org.apache.archiva.components.cache.Cache;
import org.apache.archiva.redback.configuration.UserConfiguration;
import org.apache.archiva.redback.configuration.UserConfigurationKeys;
import org.apache.archiva.redback.rbac.AbstractRBACManager;
import org.apache.archiva.redback.rbac.AbstractRole;
import org.apache.archiva.redback.rbac.Operation;
import org.apache.archiva.redback.rbac.Permission;
import org.apache.archiva.redback.rbac.RBACManager;
import org.apache.archiva.redback.rbac.RBACManagerListener;
import org.apache.archiva.redback.rbac.RBACObjectAssertions;
import org.apache.archiva.redback.rbac.RbacManagerException;
import org.apache.archiva.redback.rbac.RbacObjectInvalidException;
import org.apache.archiva.redback.rbac.RbacObjectNotFoundException;
import org.apache.archiva.redback.rbac.RbacPermanentException;
import org.apache.archiva.redback.rbac.Resource;
import org.apache.archiva.redback.rbac.Role;
import org.apache.archiva.redback.rbac.UserAssignment;
import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.UserManager;
import org.apache.archiva.redback.users.UserManagerException;
import org.apache.archiva.redback.users.ldap.ctl.LdapController;
import org.apache.archiva.redback.users.ldap.ctl.LdapControllerException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* LdapRbacManager will read datas from ldap for mapping groups to role.
* Write operations will delegate to cached implementation.
*
* @author Olivier Lamy
*/
@Service("rbacManager#ldap")
public class LdapRbacManager
extends AbstractRBACManager
implements RBACManager, RBACManagerListener
{
private Logger log = LoggerFactory.getLogger( getClass() );
@Inject
@Named(value = "rbacManager#cached")
private RBACManager rbacImpl;
@Inject
@Named(value = "ldapRoleMapper#default")
private LdapRoleMapper ldapRoleMapper;
@Inject
@Named(value = "userConfiguration#default")
private UserConfiguration userConf;
@Inject
@Named(value = "userManager#ldap")
private UserManager userManager;
@Inject
private LdapConnectionFactory ldapConnectionFactory;
@Inject
private LdapController ldapController;
@Inject
@Named(value = "ldapRoleMapperConfiguration#default")
private LdapRoleMapperConfiguration ldapRoleMapperConfiguration;
@Inject
@Named(value = "cache#ldapRoles")
private Cache<String, Role> rolesCache;
@Inject
@Named(value = "cache#userAssignments")
private Cache<String, UserAssignment> userAssignmentsCache;
private boolean writableLdap = false;
@Override
@PostConstruct
public void initialize()
{
this.writableLdap = userConf.getBoolean( UserConfigurationKeys.LDAP_WRITABLE, this.writableLdap );
}
@Override
public void addChildRole( Role role, Role childRole )
throws RbacObjectInvalidException, RbacManagerException
{
this.rbacImpl.addChildRole( role, childRole );
}
@Override
public void addListener( RBACManagerListener listener )
{
super.addListener( listener );
this.rbacImpl.addListener( listener );
}
@Override
public Operation createOperation( String name )
throws RbacManagerException
{
return this.rbacImpl.createOperation( name );
}
@Override
public Permission createPermission( String name )
throws RbacManagerException
{
return this.rbacImpl.createPermission( name );
}
@Override
public Permission createPermission( String name, String operationName, String resourceIdentifier )
throws RbacManagerException
{
return this.rbacImpl.createPermission( name, operationName, resourceIdentifier );
}
@Override
public Resource createResource( String identifier )
throws RbacManagerException
{
return this.rbacImpl.createResource( identifier );
}
@Override
public Role createRole( String id, String name )
{
return this.rbacImpl.createRole( id, name );
}
@Override
public UserAssignment createUserAssignment( String username )
throws RbacManagerException
{
// TODO ldap cannot or isWritable ldap ?
return this.rbacImpl.createUserAssignment( username );
}
@Override
public void eraseDatabase()
{
if ( writableLdap )
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
ldapRoleMapper.removeAllRoles( context );
}
catch ( MappingException e )
{
log.warn( "skip error removing all roles {}", e.getMessage() );
}
catch ( LdapException e )
{
log.warn( "skip error removing all roles {}", e.getMessage() );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
this.rolesCache.clear();
this.userAssignmentsCache.clear();
this.rbacImpl.eraseDatabase();
}
/**
* @see org.apache.archiva.redback.rbac.RBACManager#getAllAssignableRoles()
*/
@Override
public List<Role> getAllAssignableRoles()
throws RbacManagerException
{
try
{
return ldapRoleMapperConfiguration.getLdapGroupMappings( ).entrySet( ).stream( ).flatMap( entry ->{
if (entry.getValue()==null) {
return Stream.empty( );
} else
{
return entry.getValue( ).stream( ).map( role -> new RoleImpl( entry.getKey( ) + role, role ) );
}
} ).collect( Collectors.toList( ) );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
}
@Override
public List<? extends Operation> getAllOperations()
throws RbacManagerException
{
return this.rbacImpl.getAllOperations();
}
@Override
public List<? extends Permission> getAllPermissions()
throws RbacManagerException
{
return this.rbacImpl.getAllPermissions();
}
@Override
public List<? extends Resource> getAllResources()
throws RbacManagerException
{
return this.rbacImpl.getAllResources();
}
@Override
public List<Role> getAllRoles()
throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> groups = ldapRoleMapper.getAllGroups( context );
return mapToRoles( groups );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
//return this.rbacImpl.getAllRoles();
}
@Override
public List<UserAssignment> getAllUserAssignments()
throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
Map<String, Collection<String>> usersWithRoles = ldapController.findUsersWithRoles( context );
List<UserAssignment> userAssignments = new ArrayList<UserAssignment>( usersWithRoles.size() );
for ( Map.Entry<String, Collection<String>> entry : usersWithRoles.entrySet() )
{
UserAssignment userAssignment = new UserAssignmentImpl( entry.getKey(), entry.getValue() );
userAssignments.add( userAssignment );
userAssignmentsCache.put( userAssignment.getPrincipal(), userAssignment );
}
return userAssignments;
}
catch ( LdapControllerException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
protected void closeLdapConnection( LdapConnection ldapConnection )
{
if ( ldapConnection != null )
{
try
{
ldapConnection.close();
}
catch ( NamingException e )
{
log.error( "Could not close connection: {}", e.getMessage( ), e );
}
}
}
protected void closeContext( DirContext context )
{
if ( context != null )
{
try
{
context.close();
}
catch ( NamingException e )
{
log.warn( "skip issue closing context: {}", e.getMessage() );
}
}
}
/**
* public Map<String, List<Permission>> getAssignedPermissionMap( String username )
* throws RbacManagerException
* {
* return this.rbacImpl.getAssignedPermissionMap( username );
* }*
*/
/*public Set<Permission> getAssignedPermissions( String username )
throws RbacObjectNotFoundException, RbacManagerException
{
// TODO here !!
return this.rbacImpl.getAssignedPermissions( username );
}*/
private List<Role> mapToRoles( List<String> groups )
throws MappingException, RbacManagerException
{
if ( groups == null || groups.isEmpty() )
{
return Collections.emptyList();
}
final Map<String, Collection<String>> mappedGroups = ldapRoleMapperConfiguration.getLdapGroupMappings();
try
{
return groups.stream( ).flatMap( group -> mappedGroups.get( group ) == null ?
( this.ldapRoleMapper.isUseDefaultRoleName( ) ? Stream.of( this.buildRole( group, group ) ) : Stream.empty( ) )
: mappedGroups.get( group ).stream( ).map( roleName -> this.buildRole( group + roleName, roleName ) ) ).collect( Collectors.toList( ) );
} catch (RuntimeException e) {
if (e.getCause() instanceof RbacManagerException)
{
throw ( (RbacManagerException) e.getCause( ) );
} else {
throw new MappingException( e.getMessage(), e );
}
}
}
private Role buildRole( String groupId, String roleName )
{
Role role = null;
try
{
role = this.rbacImpl.getRole( roleName );
}
catch ( RbacObjectNotFoundException e )
{
// if it's mapped role to a group it doesn't exist in jpa
}
catch ( RbacManagerException e )
{
throw new RuntimeException( e );
}
role = ( role == null ) ? new RoleImpl( groupId, roleName ) : role;
if ( role != null )
{
rolesCache.put( role.getName(), role );
}
return role;
}
protected List<String> getRealRoles()
throws RbacManagerException
{
List<? extends Role> roles = this.rbacImpl.getAllRoles();
List<String> roleNames = new ArrayList<String>( roles.size() );
for ( Role role : roles )
{
roleNames.add( role.getName() );
}
return roleNames;
}
@Override
public Collection<Role> getAssignedRoles( String username )
throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> roleNames = ldapRoleMapper.getRoles( username, context, getRealRoles() );
if ( roleNames.isEmpty() )
{
return Collections.emptyList();
}
List<Role> roles = new ArrayList<Role>( roleNames.size() );
for ( String name : roleNames )
{
roles.add( this.rbacImpl.getRole( name ) );// new RoleImpl( name ) );
}
return roles;
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
} finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
@Override
public Collection<Role> getAssignedRoles( UserAssignment userAssignment )
throws RbacManagerException
{
return getAssignedRoles( userAssignment.getPrincipal() );
}
@Override
public Map<String, ? extends Role> getChildRoleNames( Role role )
throws RbacManagerException
{
return this.rbacImpl.getChildRoleNames( role );
}
@Override
public Map<String, ? extends Role> getChildRoleIds( Role role ) throws RbacManagerException
{
return this.rbacImpl.getChildRoleIds( role );
}
@Override
public Map<String, ? extends Role> getParentRoleNames( Role role )
throws RbacManagerException
{
return this.rbacImpl.getParentRoleNames( role );
}
@Override
public Map<String, ? extends Role> getParentRoleIds( Role role ) throws RbacManagerException
{
return this.rbacImpl.getParentRoleIds( role );
}
//
// public Collection<Role> getEffectivelyAssignedRoles( String username )
// throws RbacManagerException
// {
// TODO here !!
// return this.rbacImpl.getEffectivelyAssignedRoles( username );
// }
//public Collection<Role> getEffectivelyUnassignedRoles( String username )
//throws RbacManagerException
//{
// TODO here !!
// return this.rbacImpl.getEffectivelyUnassignedRoles( username );
// }
@Override
public Set<? extends Role> getEffectiveRoles( Role role )
throws RbacManagerException
{
return this.rbacImpl.getEffectiveRoles( role );
}
@Override
public Resource getGlobalResource()
throws RbacManagerException
{
return this.rbacImpl.getGlobalResource();
}
@Override
public Operation getOperation( String operationName )
throws RbacManagerException
{
return this.rbacImpl.getOperation( operationName );
}
@Override
public Permission getPermission( String permissionName )
throws RbacManagerException
{
return this.rbacImpl.getPermission( permissionName );
}
@Override
public Resource getResource( String resourceIdentifier )
throws RbacManagerException
{
return this.rbacImpl.getResource( resourceIdentifier );
}
@Override
public Role getRole( String roleName )
throws RbacManagerException
{
Role role = rolesCache.get( roleName );
if ( role != null )
{
return role;
}
if ( !checkIfLdapRole( roleName ) ) return null;
role = this.rbacImpl.getRole( roleName );
if (role==null)
{
try
{
String groupName = ldapRoleMapperConfiguration.getLdapGroupMappings( ).entrySet( ).stream( )
.filter( entry -> entry.getValue( ).contains( roleName ) )
.map( entry -> entry.getKey( ) ).findFirst( ).orElseGet( String::new );
role = new RoleImpl( groupName + roleName, roleName );
}
catch ( MappingException e )
{
role = new RoleImpl( roleName );
}
};
rolesCache.put( roleName, role );
return role;
}
protected boolean checkIfLdapRole( String roleName ) throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
//verify it's a ldap group
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
if ( !ldapRoleMapper.hasRole( context, roleName ) )
{
return false;
}
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
} finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
return true;
}
@Override
public Role getRoleById( String id ) throws RbacObjectNotFoundException, RbacManagerException
{
Role role = rbacImpl.getRoleById( id );
if (role==null) {
throw new RbacObjectNotFoundException( "Role with id " + id + " not found" );
} else {
if (checkIfLdapRole( role.getName() )) {
return role;
} else {
return null;
}
}
}
@Override
public Map<String, ? extends Role> getRoles( Collection<String> roleNames )
throws RbacManagerException
{
return this.rbacImpl.getRoles( roleNames );
}
@Override
public Collection<Role> getUnassignedRoles( String username )
throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> allRoles = ldapRoleMapper.getAllRoles( context );
final List<String> userRoles = ldapRoleMapper.getRoles( username, context, getRealRoles() );
List<Role> unassignedRoles = new ArrayList<Role>();
for ( String roleName : allRoles )
{
if ( !userRoles.contains( roleName ) )
{
unassignedRoles.add( rbacImpl.getRole( roleName ) );
}
}
return unassignedRoles;
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
@Override
public UserAssignment getUserAssignment( String username )
throws RbacManagerException
{
UserAssignment ua = userAssignmentsCache.get( username );
if ( ua != null )
{
return ua;
}
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> roles = ldapRoleMapper.getRoles( username, context, getRealRoles() )
.stream( ).map( roleName -> {
try
{
return Optional.of( rbacImpl.getRole( roleName ).getId() );
}
catch ( RbacManagerException e )
{
return Optional.<String>empty( );
}
} ).filter( Optional::isPresent ).map( Optional::get ).collect( Collectors.toList() );
ua = new UserAssignmentImpl( username, roles );
userAssignmentsCache.put( username, ua );
return ua;
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
//return this.rbacImpl.getUserAssignment( username );
}
@Override
public List<? extends UserAssignment> getUserAssignmentsForRoles( Collection<String> roleIds )
throws RbacManagerException
{
// TODO from ldap
return this.rbacImpl.getUserAssignmentsForRoles( roleIds );
}
@Override
public boolean operationExists( Operation operation )
{
return this.rbacImpl.operationExists( operation );
}
@Override
public boolean operationExists( String name )
{
return this.rbacImpl.operationExists( name );
}
@Override
public boolean permissionExists( Permission permission )
{
return this.rbacImpl.permissionExists( permission );
}
@Override
public boolean permissionExists( String name )
{
return this.rbacImpl.permissionExists( name );
}
@Override
public void rbacInit( boolean freshdb )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacInit( freshdb );
}
}
@Override
public void rbacPermissionRemoved( Permission permission )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacPermissionRemoved( permission );
}
}
@Override
public void rbacPermissionSaved( Permission permission )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacPermissionSaved( permission );
}
}
@Override
public void rbacRoleRemoved( Role role )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacRoleRemoved( role );
}
}
@Override
public void rbacRoleSaved( Role role )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacRoleSaved( role );
}
}
@Override
public void rbacUserAssignmentRemoved( UserAssignment userAssignment )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacUserAssignmentRemoved( userAssignment );
}
}
@Override
public void rbacUserAssignmentSaved( UserAssignment userAssignment )
{
if ( rbacImpl instanceof RBACManagerListener )
{
( (RBACManagerListener) this.rbacImpl ).rbacUserAssignmentSaved( userAssignment );
}
}
@Override
public void removeListener( RBACManagerListener listener )
{
this.rbacImpl.removeListener( listener );
}
@Override
public void removeOperation( Operation operation )
throws RbacManagerException
{
this.rbacImpl.removeOperation( operation );
}
@Override
public void removeOperation( String operationName )
throws RbacManagerException
{
this.rbacImpl.removeOperation( operationName );
}
@Override
public void removePermission( Permission permission )
throws RbacManagerException
{
this.rbacImpl.removePermission( permission );
}
@Override
public void removePermission( String permissionName )
throws RbacManagerException
{
this.rbacImpl.removePermission( permissionName );
}
@Override
public void removeResource( Resource resource )
throws RbacManagerException
{
this.rbacImpl.removeResource( resource );
}
@Override
public void removeResource( String resourceIdentifier )
throws RbacManagerException
{
this.rbacImpl.removeResource( resourceIdentifier );
}
@Override
public void removeRole( Role role )
throws RbacManagerException
{
RBACObjectAssertions.assertValid( role );
if ( role.isPermanent() )
{
throw new RbacPermanentException( "Unable to delete permanent role [" + role.getName() + "]" );
}
rolesCache.remove( role.getName() );
if ( writableLdap )
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
ldapRoleMapper.removeRole( role.getName(), context );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
} finally {
closeContext( context );
closeLdapConnection( ldapConnection );
}
fireRbacRoleRemoved( role );
}
}
@Override
public void removeRole( String roleName )
throws RbacManagerException
{
if ( roleName == null )
{
return;
}
removeRole( new RoleImpl( roleName ) );
}
@Override
public void removeUserAssignment( String username )
throws RbacManagerException
{
// TODO ldap cannot or isWritable ldap ?
userAssignmentsCache.remove( username );
this.rbacImpl.removeUserAssignment( username );
}
@Override
public void removeUserAssignment( UserAssignment userAssignment )
throws RbacManagerException
{
if ( userAssignment != null )
{
userAssignmentsCache.remove( userAssignment.getPrincipal() );
}
// TODO ldap cannot or isWritable ldap ?
this.rbacImpl.removeUserAssignment( userAssignment );
}
@Override
public boolean resourceExists( Resource resource )
{
return this.rbacImpl.resourceExists( resource );
}
@Override
public boolean resourceExists( String identifier )
{
return this.rbacImpl.resourceExists( identifier );
}
@Override
public boolean roleExists( Role role )
throws RbacManagerException
{
if ( role == null )
{
return false;
}
return roleExists( role.getName() );
}
@Override
public boolean roleExists( String name )
throws RbacManagerException
{
if ( StringUtils.isEmpty( name ) )
{
return false;
}
if ( rolesCache.get( name ) != null )
{
return true;
}
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
if ( rolesCache.hasKey( name ) )
{
return true;
}
return ldapRoleMapper.hasRole( context, name );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
@Override
public boolean roleExistsById( String id ) throws RbacManagerException
{
Role role = rbacImpl.getRoleById( id );
if (role==null) {
return false;
} else {
return roleExists( role.getName() );
}
}
@Override
public Operation saveOperation( Operation operation )
throws RbacManagerException
{
return this.rbacImpl.saveOperation( operation );
}
@Override
public Permission savePermission( Permission permission )
throws RbacManagerException
{
return this.rbacImpl.savePermission( permission );
}
@Override
public Resource saveResource( Resource resource )
throws RbacManagerException
{
return this.rbacImpl.saveResource( resource );
}
@Override
public synchronized Role saveRole( Role role )
throws RbacManagerException
{
if ( writableLdap )
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
ldapRoleMapper.saveRole( role.getName(), context );
if ( !role.getChildRoleNames().isEmpty() )
{
for ( String roleName : role.getChildRoleNames() )
{
ldapRoleMapper.saveRole( roleName, context );
}
}
fireRbacRoleSaved( role );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
}
role = this.rbacImpl.saveRole( role );
rolesCache.put( role.getName(), role );
return role;
//return new RoleImpl( role.getName(), role.getPermissions() );
}
@Override
public synchronized void saveRoles( Collection<Role> roles )
throws RbacManagerException
{
if ( writableLdap )
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
for ( Role role : roles )
{
ldapRoleMapper.saveRole( role.getName(), context );
fireRbacRoleSaved( role );
}
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
}
this.rbacImpl.saveRoles( roles );
}
@Override
public UserAssignment saveUserAssignment( UserAssignment userAssignment )
throws RbacManagerException
{
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
if ( !userManager.userExists( userAssignment.getPrincipal() ) )
{
User user = userManager.createUser( userAssignment.getPrincipal(), null, null );
userManager.addUser( user );
}
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> allRoles = ldapRoleMapper.getAllRoles( context );
List<String> currentUserRoles =
ldapRoleMapper.getRoles( userAssignment.getPrincipal(), context, getRealRoles() );
Map<String, String> currentUserIds = currentUserRoles.stream( ).map( roleName -> {
try
{
return Optional.of( rbacImpl.getRole( roleName ) );
}
catch ( RbacManagerException e )
{
return Optional.<Role>empty( );
}
} ).filter( Optional::isPresent ).map(Optional::get)
.collect( Collectors.toMap( Role::getName, Role::getId ) );
for ( String roleId : userAssignment.getRoleIds() )
{
Role rbacRole = rbacImpl.getRoleById( roleId );
String roleName = rbacRole.getName( );
if ( !currentUserRoles.contains( roleName ) && writableLdap )
{
// role exists in ldap ?
if ( !allRoles.contains( roleName ) )
{
ldapRoleMapper.saveRole( roleName, context );
allRoles.add( roleName );
}
ldapRoleMapper.saveUserRole( roleName, userAssignment.getPrincipal(), context );
currentUserRoles.add( roleName );
currentUserIds.put( roleName, rbacRole.getId( ) );
}
}
for ( String roleName : currentUserRoles )
{
if ( !userAssignment.getRoleIds().contains( currentUserIds.get(roleName) ) && writableLdap )
{
ldapRoleMapper.removeUserRole( roleName, userAssignment.getPrincipal(), context );
}
}
userAssignmentsCache.put( userAssignment.getPrincipal(), userAssignment );
return userAssignment;
}
catch ( UserManagerException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( MappingException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
catch ( LdapException e )
{
throw new RbacManagerException( e.getMessage(), e );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
}
@Override
public boolean userAssignmentExists( String principal )
{
if ( userAssignmentsCache.hasKey( principal ) )
{
return true;
}
LdapConnection ldapConnection = null;
DirContext context = null;
try
{
ldapConnection = ldapConnectionFactory.getConnection();
context = ldapConnection.getDirContext();
List<String> roles = ldapRoleMapper.getRoles( principal, context, getRealRoles() );
if ( roles == null || roles.isEmpty() )
{
return false;
}
return true;
}
catch ( RbacManagerException e )
{
log.warn( "fail to call userAssignmentExists: {}", e.getMessage() );
}
catch ( LdapException e )
{
log.warn( "fail to call userAssignmentExists: {}", e.getMessage() );
}
catch ( MappingException e )
{
log.warn( "fail to call userAssignmentExists: {}", e.getMessage() );
}
finally
{
closeContext( context );
closeLdapConnection( ldapConnection );
}
return false;
}
@Override
public boolean userAssignmentExists( UserAssignment assignment )
{
if ( assignment == null )
{
return false;
}
return this.userAssignmentExists( assignment.getPrincipal() );
}
public RBACManager getRbacImpl()
{
return rbacImpl;
}
public void setRbacImpl( RBACManager rbacImpl )
{
this.rbacImpl = rbacImpl;
}
public boolean isWritableLdap()
{
return writableLdap;
}
public void setWritableLdap( boolean writableLdap )
{
this.writableLdap = writableLdap;
}
public LdapRoleMapper getLdapRoleMapper()
{
return ldapRoleMapper;
}
public void setLdapRoleMapper( LdapRoleMapper ldapRoleMapper )
{
this.ldapRoleMapper = ldapRoleMapper;
}
private static class RoleImpl
extends AbstractRole
{
private String name;
private String description;
private String id="";
private String modelId="";
private boolean isTemplateInstance=false;
private String resource="";
private List<Permission> permissions = new ArrayList<>();
private List<String> childRoleNames = new ArrayList<>();
private List<String> childRoleIds = new ArrayList<>( );
private RoleImpl( String name )
{
this.name = name;
this.id = name;
}
private RoleImpl(String id, String name) {
this.id = id;
this.name = name;
}
private RoleImpl( String name, List<Permission> permissions )
{
this.name = name;
this.permissions = permissions;
}
@Override
public void addPermission( Permission permission )
{
this.permissions.add( permission );
}
@Override
public void addChildRoleName( String name )
{
this.childRoleNames.add( name );
}
@Override
public List<String> getChildRoleNames()
{
return this.childRoleNames;
}
@Override
public void addChildRoleId( String id )
{
this.childRoleIds.add( id );
}
@Override
public List<String> getChildRoleIds( )
{
return this.childRoleIds;
}
@Override
public String getDescription()
{
return this.description;
}
@Override
public String getName()
{
return this.name;
}
@Override
public List<Permission> getPermissions()
{
return this.permissions;
}
@Override
public boolean isAssignable()
{
return true;
}
@Override
public void removePermission( Permission permission )
{
this.permissions.remove( permission );
}
@Override
public void setAssignable( boolean assignable )
{
// no op
}
@Override
public void setChildRoleNames( List<String> names )
{
this.childRoleNames = names;
}
@Override
public void setChildRoleIds( List<String> ids )
{
}
@Override
public void setDescription( String description )
{
this.description = description;
}
@Override
public void setName( String name )
{
this.name = name;
}
@Override
public void setPermissions( List<Permission> permissions )
{
this.permissions = permissions;
}
@Override
public boolean isPermanent()
{
return true;
}
@Override
public void setPermanent( boolean permanent )
{
// no op
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append( "RoleImpl" );
sb.append( "{name='" ).append( name ).append( '\'' );
sb.append( '}' );
return sb.toString();
}
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || getClass() != o.getClass() )
{
return false;
}
RoleImpl role = (RoleImpl) o;
if ( name != null ? !name.equals( role.name ) : role.name != null )
{
return false;
}
return true;
}
@Override
public int hashCode()
{
return name != null ? name.hashCode() : 0;
}
@Override
public String getId( )
{
return id;
}
@Override
public void setId( String id )
{
if (id==null) {
this.id = "";
} else
{
this.id = id;
}
}
@Override
public String getModelId( )
{
return modelId;
}
@Override
public void setModelId( String modelId )
{
if (modelId==null) {
this.modelId = "";
} else
{
this.modelId = modelId;
}
}
@Override
public boolean isTemplateInstance( )
{
return isTemplateInstance;
}
@Override
public void setTemplateInstance( boolean templateInstance )
{
isTemplateInstance = templateInstance;
}
@Override
public String getResource( )
{
return resource;
}
@Override
public void setResource( String resource )
{
if (resource==null) {
this.resource = "";
} else
{
this.resource = resource;
}
}
}
private static class UserAssignmentImpl
implements UserAssignment
{
private String username;
private List<String> roleIds;
private boolean permanent;
private UserAssignmentImpl( String username, Collection<String> roleIds )
{
this.username = username;
if ( roleIds == null )
{
this.roleIds = new ArrayList<>( );
}
else
{
this.roleIds = new ArrayList<>( roleIds );
}
}
@Override
public String getPrincipal()
{
return this.username;
}
@Override
public List<String> getRoleNames()
{
return this.roleIds;
}
@Override
public List<String> getRoleIds( )
{
return this.roleIds;
}
@Override
public void addRoleName( Role role )
{
if ( role == null )
{
return;
}
this.roleIds.add( role.getName() );
}
@Override
public void addRoleName( String roleName )
{
if ( roleName == null )
{
return;
}
this.roleIds.add( roleName );
}
@Override
public void addRoleId( Role role )
{
if ( role == null )
{
return;
}
this.roleIds.add( role.getId() );
}
@Override
public void addRoleId( String roleId )
{
if ( roleId == null )
{
return;
}
this.roleIds.add( roleId );
}
@Override
public void removeRoleName( Role role )
{
if ( role == null )
{
return;
}
this.roleIds.remove( role.getName() );
}
@Override
public void removeRoleName( String roleName )
{
if ( roleName == null )
{
return;
}
this.roleIds.remove( roleName );
}
@Override
public void removeRoleId( Role role )
{
if ( role == null )
{
return;
}
this.roleIds.remove( role.getId() );
}
@Override
public void removeRoleId( String roleId )
{
if ( roleId == null )
{
return;
}
this.roleIds.remove( roleId );
}
@Override
public void setPrincipal( String principal )
{
this.username = principal;
}
@Override
public void setRoleNames( List<String> roles )
{
this.roleIds = roles;
}
@Override
public void setRoleIds( List<String> roles )
{
this.roleIds = roles;
}
@Override
public boolean isPermanent()
{
return this.permanent;
}
@Override
public void setPermanent( boolean permanent )
{
this.permanent = permanent;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append( "UserAssignmentImpl" );
sb.append( "{username='" ).append( username ).append( '\'' );
sb.append( ", roleNames=" ).append( roleIds );
sb.append( ", permanent=" ).append( permanent );
sb.append( '}' );
return sb.toString();
}
}
@Override
public boolean isFinalImplementation()
{
return true;
}
@Override
public String getDescriptionKey()
{
return "archiva.redback.rbacmanager.ldap";
}
@Override
public boolean isReadOnly()
{
return !writableLdap;
}
}