001package org.apache.archiva.redback.users.ldap; 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 022 023import org.apache.archiva.redback.common.ldap.connection.DefaultLdapConnection; 024import org.apache.archiva.redback.common.ldap.connection.LdapConnection; 025import org.apache.archiva.redback.common.ldap.user.LdapUser; 026import org.apache.archiva.redback.common.ldap.user.UserMapper; 027import org.apache.archiva.redback.configuration.UserConfiguration; 028import org.apache.archiva.redback.configuration.UserConfigurationKeys; 029import org.apache.archiva.redback.users.AbstractUserManager; 030import org.apache.archiva.redback.users.User; 031import org.apache.archiva.redback.users.UserExistsException; 032import org.apache.archiva.redback.users.UserManager; 033import org.apache.archiva.redback.users.UserManagerException; 034import org.apache.archiva.redback.users.UserNotFoundException; 035import org.apache.archiva.redback.common.ldap.MappingException; 036import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory; 037import org.apache.archiva.redback.common.ldap.connection.LdapException; 038import org.apache.archiva.redback.users.UserQuery; 039import org.apache.archiva.redback.users.ldap.ctl.LdapController; 040import org.apache.archiva.redback.users.ldap.ctl.LdapControllerException; 041import org.apache.archiva.redback.users.ldap.service.LdapCacheService; 042import org.springframework.stereotype.Service; 043 044import javax.annotation.PostConstruct; 045import javax.inject.Inject; 046import javax.inject.Named; 047import javax.naming.NamingException; 048import javax.naming.directory.DirContext; 049import java.util.ArrayList; 050import java.util.Collections; 051import java.util.Date; 052import java.util.List; 053 054/** 055 * @author jesse 056 */ 057@Service("userManager#ldap") 058public class LdapUserManager 059 extends AbstractUserManager 060 implements UserManager 061{ 062 @Inject 063 @Named(value = "ldapConnectionFactory#configurable") 064 private LdapConnectionFactory connectionFactory; 065 066 @Inject 067 private LdapController controller; 068 069 @Inject 070 @Named(value = "userMapper#ldap") 071 private UserMapper mapper; 072 073 @Inject 074 @Named(value = "userConfiguration#default") 075 private UserConfiguration userConf; 076 077 @Inject 078 private LdapCacheService ldapCacheService; 079 080 private User guestUser; 081 082 private boolean writableLdap = false; 083 084 @PostConstruct 085 public void initialize() 086 { 087 this.writableLdap = userConf.getBoolean( UserConfigurationKeys.LDAP_WRITABLE, this.writableLdap ); 088 controller.initialize(); 089 } 090 091 public boolean isReadOnly() 092 { 093 return !this.writableLdap; 094 } 095 096 public User addUser( User user ) 097 throws UserManagerException 098 { 099 try 100 { 101 return addUser( user, true ); 102 } 103 catch ( LdapException e ) 104 { 105 throw new UserManagerException( e.getMessage(), e ); 106 } 107 } 108 109 public void addUserUnchecked( User user ) 110 throws UserManagerException 111 { 112 try 113 { 114 addUser( user, false ); 115 } 116 catch ( LdapException e ) 117 { 118 throw new UserManagerException( e.getMessage(), e ); 119 } 120 } 121 122 private User addUser( User user, boolean checked ) 123 throws LdapException 124 { 125 if ( user == null ) 126 { 127 return null; 128 } 129 try 130 { 131 if (checked && userExists( user.getUsername() )){ 132 throw new UserExistsException( "User exists already " + user.getUsername( ) ); 133 } 134 } 135 catch ( UserManagerException e ) 136 { 137 throw new LdapException( "Unexpected LDAP error " + e.getMessage( ) ); 138 } 139 140 if ( isReadOnly() && GUEST_USERNAME.equals( user.getUsername() ) ) 141 { 142 guestUser = user; 143 return guestUser; 144 } 145 146 user.setAccountCreationDate( new Date( ) ); 147 148 LdapConnection ldapConnection = getLdapConnection(); 149 try 150 { 151 DirContext context = ldapConnection.getDirContext(); 152 controller.createUser( user, context, checked ); 153 } 154 catch ( LdapControllerException e ) 155 { 156 log.error( "Error mapping user: {} to LDAP attributes.", user.getUsername(), e ); 157 } 158 catch ( MappingException e ) 159 { 160 log.error( "Error mapping user: {} to LDAP attributes.", user.getUsername(), e ); 161 } 162 finally 163 { 164 closeLdapConnection( ldapConnection ); 165 } 166 return user; 167 } 168 169 public User createUser( String username, String fullName, String emailAddress ) 170 { 171 return mapper.newUserInstance( username, fullName, emailAddress ); 172 } 173 174 public UserQuery createUserQuery() 175 { 176 return new LdapUserQuery(); 177 } 178 179 180 public void deleteUser( String username ) 181 throws UserNotFoundException, UserManagerException 182 { 183 if ( username != null ) 184 { 185 clearFromCache( username ); 186 } 187 LdapConnection ldapConnection = null; 188 try 189 { 190 ldapConnection = getLdapConnection(); 191 DirContext context = ldapConnection.getDirContext(); 192 controller.removeUser( username, context ); 193 } 194 catch ( LdapControllerException e ) 195 { 196 log.error( "Failed to delete user: {}", username, e ); 197 } 198 catch ( LdapException e ) 199 { 200 throw new UserManagerException( e.getMessage(), e ); 201 } 202 finally 203 { 204 closeLdapConnection( ldapConnection ); 205 } 206 } 207 208 public void eraseDatabase() 209 { 210 // TODO Implement erase! 211 } 212 213 @Override 214 public User findUser( String username, boolean useCache ) 215 throws UserNotFoundException, UserManagerException 216 { 217 if ( username == null ) 218 { 219 throw new UserNotFoundException( "Unable to find user based on null username." ); 220 } 221 222 if ( useCache ) 223 { 224 // REDBACK-289/MRM-1488 225 // look for the user in the cache first 226 LdapUser ldapUser = ldapCacheService.getUser( username ); 227 if ( ldapUser != null ) 228 { 229 log.debug( "User {} found in cache.", username ); 230 return ldapUser; 231 } 232 } 233 LdapConnection ldapConnection = null; 234 235 try 236 { 237 ldapConnection = getLdapConnection(); 238 DirContext context = ldapConnection.getDirContext(); 239 User user = controller.getUser( username, context ); 240 if ( user == null ) 241 { 242 throw new UserNotFoundException( "user with name " + username + " not found " ); 243 } 244 245 // REDBACK-289/MRM-1488 246 log.debug( "Adding user {} to cache..", username ); 247 248 ldapCacheService.addUser( (LdapUser) user ); 249 250 return user; 251 } 252 catch ( LdapControllerException e ) 253 { 254 log.error( "Failed to find user: {}", username, e ); 255 return null; 256 } 257 catch ( LdapException e ) 258 { 259 throw new UserManagerException( e.getMessage(), e ); 260 } 261 catch ( MappingException e ) 262 { 263 log.error( "Failed to map user: {}", username, e ); 264 return null; 265 } 266 finally 267 { 268 closeLdapConnection( ldapConnection ); 269 } 270 } 271 272 public User findUser( String username ) 273 throws UserNotFoundException, UserManagerException 274 { 275 return findUser( username, true ); 276 } 277 278 public List<User> findUsersByEmailKey( String emailKey, boolean orderAscending ) 279 throws UserManagerException 280 { 281 LdapUserQuery query = new LdapUserQuery(); 282 query.setEmail( emailKey ); 283 query.setOrderBy( UserQuery.ORDER_BY_EMAIL ); 284 query.setAscending( orderAscending ); 285 return findUsersByQuery( query ); 286 } 287 288 public List<User> findUsersByFullNameKey( String fullNameKey, boolean orderAscending ) 289 throws UserManagerException 290 { 291 LdapUserQuery query = new LdapUserQuery(); 292 query.setFullName( fullNameKey ); 293 query.setOrderBy( UserQuery.ORDER_BY_FULLNAME ); 294 query.setAscending( orderAscending ); 295 return findUsersByQuery( query ); 296 } 297 298 public List<User> findUsersByQuery( UserQuery query ) 299 throws UserManagerException 300 { 301 if ( query == null ) 302 { 303 return Collections.emptyList(); 304 } 305 306 LdapConnection ldapConnection = null; 307 308 try 309 { 310 ldapConnection = getLdapConnection(); 311 DirContext context = ldapConnection.getDirContext(); 312 return controller.getUsersByQuery( (LdapUserQuery) query, context ); 313 } 314 catch ( LdapControllerException e ) 315 { 316 log.error( "Failed to find user", e ); 317 return null; 318 } 319 catch ( MappingException e ) 320 { 321 log.error( "Failed to map user", e ); 322 return null; 323 } 324 catch ( LdapException e ) 325 { 326 throw new UserManagerException( e.getMessage(), e ); 327 } 328 finally 329 { 330 closeLdapConnection( ldapConnection ); 331 } 332 } 333 334 /** 335 * @see org.apache.archiva.redback.users.UserManager#findUsersByUsernameKey(java.lang.String, boolean) 336 */ 337 public List<User> findUsersByUsernameKey( String usernameKey, boolean orderAscending ) 338 throws UserManagerException 339 { 340 LdapUserQuery query = new LdapUserQuery(); 341 query.setUsername( usernameKey ); 342 query.setOrderBy( UserQuery.ORDER_BY_USERNAME ); 343 query.setAscending( orderAscending ); 344 return findUsersByQuery( query ); 345 } 346 347 public String getId() 348 { 349 return "ldap"; 350 } 351 352 /** 353 * @see org.apache.archiva.redback.users.UserManager#getUsers() 354 */ 355 public List<User> getUsers() 356 { 357 LdapConnection ldapConnection = null; 358 359 try 360 { 361 ldapConnection = getLdapConnection(); 362 DirContext context = ldapConnection.getDirContext(); 363 List<User> users = new ArrayList<User>( controller.getUsers( context ) ); 364 //We add the guest user because it isn't in LDAP 365 try 366 { 367 User u = getGuestUser(); 368 if ( u != null ) 369 { 370 users.add( u ); 371 } 372 } 373 catch ( UserNotFoundException e ) 374 { 375 //Nothing to do 376 } 377 return users; 378 } 379 /*catch ( LdapException e ) 380 { 381 throw new UserManagerException( e.getMessage(), e ); 382 }*/ 383 catch ( Exception e ) 384 { 385 log.error( e.getMessage(), e ); 386 } 387 finally 388 { 389 closeLdapConnection( ldapConnection ); 390 } 391 return Collections.emptyList(); 392 } 393 394 public List<User> getUsers( boolean orderAscending ) 395 { 396 return getUsers(); 397 } 398 399 public User updateUser( User user ) 400 throws UserNotFoundException, UserManagerException 401 { 402 return updateUser( user, false ); 403 } 404 405 public User updateUser( User user, boolean passwordChangeRequired ) 406 throws UserNotFoundException, UserManagerException 407 { 408 if ( user != null ) 409 { 410 clearFromCache( user.getUsername() ); 411 } 412 413 LdapConnection ldapConnection = null; 414 415 try 416 { 417 ldapConnection = getLdapConnection(); 418 DirContext context = ldapConnection.getDirContext(); 419 controller.updateUser( user, context ); 420 } 421 catch ( LdapControllerException e ) 422 { 423 log.error( "Failed to update user: {}", user.getUsername(), e ); 424 } 425 catch ( MappingException e ) 426 { 427 log.error( "Failed to update user: {}", user.getUsername(), e ); 428 } 429 catch ( LdapException e ) 430 { 431 throw new UserManagerException( e.getMessage(), e ); 432 } 433 finally 434 { 435 closeLdapConnection( ldapConnection ); 436 } 437 return user; 438 } 439 440 public boolean userExists( String principal ) 441 throws UserManagerException 442 { 443 if ( principal == null ) 444 { 445 return false; 446 } 447 448 // REDBACK-289/MRM-1488 449 // look for the user in the cache first 450 LdapUser ldapUser = ldapCacheService.getUser( principal ); 451 if ( ldapUser != null ) 452 { 453 log.debug( "User {} found in cache.", principal ); 454 return true; 455 } 456 457 LdapConnection ldapConnection = null; 458 459 try 460 { 461 ldapConnection = getLdapConnection(); 462 DirContext context = ldapConnection.getDirContext(); 463 return controller.userExists( principal, context ); 464 } 465 catch ( LdapControllerException e ) 466 { 467 log.warn( "Failed to search for user: {}", principal, e ); 468 return false; 469 } 470 catch ( LdapException e ) 471 { 472 throw new UserManagerException( e.getMessage(), e ); 473 } 474 finally 475 { 476 closeLdapConnection( ldapConnection ); 477 } 478 } 479 480 private LdapConnection getLdapConnection() 481 throws LdapException 482 { 483 try 484 { 485 return connectionFactory.getConnection(); 486 } 487 catch ( LdapException e ) 488 { 489 log.warn( "failed to get a ldap connection {}", e.getMessage(), e ); 490 throw new LdapException( "failed to get a ldap connection " + e.getMessage(), e ); 491 } 492 } 493 494 private void closeLdapConnection( LdapConnection ldapConnection ) 495 { 496 if ( ldapConnection != null ) 497 { 498 try 499 { 500 ldapConnection.close(); 501 } 502 catch ( NamingException e ) 503 { 504 log.error( "Could not close connection: {}", e.getMessage( ), e ); 505 } 506 } 507 } 508 509 // REDBACK-289/MRM-1488 510 private void clearFromCache( String username ) 511 { 512 log.debug( "Removing user {} from cache..", username ); 513 ldapCacheService.removeUser( username ); 514 515 log.debug( "Removing userDn for user {} from cache..", username ); 516 ldapCacheService.removeLdapUserDn( username ); 517 } 518 519 public boolean isFinalImplementation() 520 { 521 return true; 522 } 523 524 public String getDescriptionKey() 525 { 526 return "archiva.redback.usermanager.ldap"; 527 } 528}