parent
e15eec7fdd
commit
488a7d720b
@ -0,0 +1,133 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited |
||||||
|
* |
||||||
|
* Licensed 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.libresonic.player.security; |
||||||
|
|
||||||
|
import org.libresonic.player.Logger; |
||||||
|
import org.libresonic.player.domain.User; |
||||||
|
import org.libresonic.player.service.SecurityService; |
||||||
|
import org.libresonic.player.service.SettingsService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.ldap.core.DirContextAdapter; |
||||||
|
import org.springframework.ldap.core.DirContextOperations; |
||||||
|
import org.springframework.security.authentication.BadCredentialsException; |
||||||
|
import org.springframework.security.core.GrantedAuthority; |
||||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||||
|
import org.springframework.security.ldap.ppolicy.PasswordPolicyControl; |
||||||
|
import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl; |
||||||
|
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl; |
||||||
|
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
@Component |
||||||
|
public class LibresonicUserDetailsContextMapper implements UserDetailsContextMapper { |
||||||
|
// ~ Instance fields
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(LibresonicUserDetailsContextMapper.class); |
||||||
|
private String passwordAttributeName = "userPassword"; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
SecurityService securityService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
SettingsService settingsService; |
||||||
|
|
||||||
|
// ~ Methods
|
||||||
|
// ========================================================================================================
|
||||||
|
|
||||||
|
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, |
||||||
|
Collection<? extends GrantedAuthority> authorities) { |
||||||
|
String dn = ctx.getNameInNamespace(); |
||||||
|
|
||||||
|
logger.debug("Mapping user details from context with DN: " + dn); |
||||||
|
|
||||||
|
// User must be defined in Libresonic, unless auto-shadowing is enabled.
|
||||||
|
User user = securityService.getUserByName(username, false); |
||||||
|
if (user == null && !settingsService.isLdapAutoShadowing()) { |
||||||
|
throw new BadCredentialsException("User does not exist."); |
||||||
|
} |
||||||
|
|
||||||
|
if (user == null) { |
||||||
|
User newUser = new User(username, "", null, true, 0L, 0L, 0L); |
||||||
|
newUser.setStreamRole(true); |
||||||
|
newUser.setSettingsRole(true); |
||||||
|
securityService.createUser(newUser); |
||||||
|
logger.info("Created local user '" + username + "' for DN " + dn); |
||||||
|
user = securityService.getUserByName(username, false); |
||||||
|
} |
||||||
|
|
||||||
|
// LDAP authentication must be enabled for the given user.
|
||||||
|
if (!user.isLdapAuthenticated()) { |
||||||
|
throw new BadCredentialsException("LDAP authentication disabled for user."); |
||||||
|
} |
||||||
|
|
||||||
|
LdapUserDetailsImpl.Essence essence = new LdapUserDetailsImpl.Essence(); |
||||||
|
essence.setDn(dn); |
||||||
|
|
||||||
|
Object passwordValue = ctx.getObjectAttribute(passwordAttributeName); |
||||||
|
|
||||||
|
if (passwordValue != null) { |
||||||
|
essence.setPassword(mapPassword(passwordValue)); |
||||||
|
} |
||||||
|
|
||||||
|
essence.setUsername(user.getUsername()); |
||||||
|
|
||||||
|
// Add the supplied authorities
|
||||||
|
for (GrantedAuthority authority : securityService.getGrantedAuthorities(user.getUsername())) { |
||||||
|
essence.addAuthority(authority); |
||||||
|
} |
||||||
|
|
||||||
|
// Check for PPolicy data
|
||||||
|
|
||||||
|
PasswordPolicyResponseControl ppolicy = (PasswordPolicyResponseControl) ctx |
||||||
|
.getObjectAttribute(PasswordPolicyControl.OID); |
||||||
|
|
||||||
|
if (ppolicy != null) { |
||||||
|
essence.setTimeBeforeExpiration(ppolicy.getTimeBeforeExpiration()); |
||||||
|
essence.setGraceLoginsRemaining(ppolicy.getGraceLoginsRemaining()); |
||||||
|
} |
||||||
|
|
||||||
|
return essence.createUserDetails(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) { |
||||||
|
throw new UnsupportedOperationException( |
||||||
|
"LdapUserDetailsMapper only supports reading from a context. Please" |
||||||
|
+ "use a subclass if mapUserToContext() is required."); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Extension point to allow customized creation of the user's password from the |
||||||
|
* attribute stored in the directory. |
||||||
|
* |
||||||
|
* @param passwordValue the value of the password attribute |
||||||
|
* @return a String representation of the password. |
||||||
|
*/ |
||||||
|
protected String mapPassword(Object passwordValue) { |
||||||
|
|
||||||
|
if (!(passwordValue instanceof String)) { |
||||||
|
// Assume it's binary
|
||||||
|
passwordValue = new String((byte[]) passwordValue); |
||||||
|
} |
||||||
|
|
||||||
|
return (String) passwordValue; |
||||||
|
|
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue