/**
* Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.security.internal.realms;
import org.seedstack.seed.security.AuthenticationException;
import org.seedstack.seed.security.AuthenticationInfo;
import org.seedstack.seed.security.AuthenticationToken;
import org.seedstack.seed.security.IncorrectCredentialsException;
import org.seedstack.seed.security.Realm;
import org.seedstack.seed.security.RoleMapping;
import org.seedstack.seed.security.RolePermissionResolver;
import org.seedstack.seed.security.SecurityConfig;
import org.seedstack.seed.security.UnknownAccountException;
import org.seedstack.seed.security.UnsupportedTokenException;
import org.seedstack.seed.security.UsernamePasswordToken;
import org.seedstack.seed.security.principals.PrincipalProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A realm that authentifies users and gives authorities with a configuration file.
*/
public class ConfigurationRealm implements Realm {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationRealm.class);
/**
* props section suffix
*/
public static final String USER_SECTION_NAME = "users";
private final Set<ConfigurationUser> users = new HashSet<>();
private RoleMapping roleMapping;
private RolePermissionResolver rolePermissionResolver;
@Override
public Set<String> getRealmRoles(PrincipalProvider<?> identityPrincipal, Collection<PrincipalProvider<?>> otherPrincipals) {
ConfigurationUser user = findUser(identityPrincipal.getPrincipal().toString());
if (user != null) {
return user.roles;
}
return Collections.emptySet();
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (!(token instanceof UsernamePasswordToken)) {
throw new UnsupportedTokenException("ConfigurationRealm only supports UsernamePasswordToken");
}
UsernamePasswordToken userNamePasswordToken = (UsernamePasswordToken) token;
ConfigurationUser user = findUser(userNamePasswordToken.getUsername());
if (user == null) {
throw new UnknownAccountException("Unknown user " + userNamePasswordToken.getUsername());
}
if (!user.password.equals(new String(userNamePasswordToken.getPassword()))) {
throw new IncorrectCredentialsException();
}
return new AuthenticationInfo(userNamePasswordToken.getUsername(), userNamePasswordToken.getPassword());
}
@Inject
void readConfiguration(SecurityConfig securityConfig) {
if (securityConfig.getUsers().isEmpty()) {
LOGGER.warn("{} defined, but the configuration defines no user", getClass().getSimpleName());
} else {
users.clear();
for (Map.Entry<String, SecurityConfig.UserConfig> entry : securityConfig.getUsers().entrySet()) {
ConfigurationUser user = new ConfigurationUser(entry.getKey());
SecurityConfig.UserConfig userConfig = entry.getValue();
user.password = userConfig.getPassword();
user.roles.addAll(userConfig.getRoles());
users.add(user);
}
}
}
@Override
public RoleMapping getRoleMapping() {
return this.roleMapping;
}
@Override
public RolePermissionResolver getRolePermissionResolver() {
return this.rolePermissionResolver;
}
/**
* Setter roleMapping
*
* @param roleMapping the role mapping
*/
@Inject
public void setRoleMapping(@Named("ConfigurationRealm-role-mapping") RoleMapping roleMapping) {
this.roleMapping = roleMapping;
}
/**
* Setter rolePermissionResolver
*
* @param rolePermissionResolver the rolePermissionResolver
*/
@Inject
public void setRolePermissionResolver(@Named("ConfigurationRealm-role-permission-resolver") RolePermissionResolver rolePermissionResolver) {
this.rolePermissionResolver = rolePermissionResolver;
}
private ConfigurationUser findUser(String username) {
for (ConfigurationUser user : users) {
if (user.username.equals(username)) {
return user;
}
}
return null;
}
@Override
public Class<? extends AuthenticationToken> supportedToken() {
return UsernamePasswordToken.class;
}
/**
* Class to represent a user from the configuration. In the file, key is the name, first value is the password, following values are the roles.
*
* */
static class ConfigurationUser {
private final String username;
private final Set<String> roles = new HashSet<>();
private String password;
ConfigurationUser(String username) {
this.username = username;
}
public Set<String> getRoles() {
return roles;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConfigurationUser configurationUser = (ConfigurationUser) o;
return username.equals(configurationUser.username);
}
@Override
public int hashCode() {
return username.hashCode();
}
}
}