Merge pull request #304 from mposolda/ldap
KEYCLOAK-388 - Auth SPI should be able to differentiate between the INVA...
This commit is contained in:
commit
434dec2318
11 changed files with 154 additions and 23 deletions
|
@ -122,6 +122,15 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'RealmSMTPSettingsCtrl'
|
controller : 'RealmSMTPSettingsCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/ldap-settings', {
|
||||||
|
templateUrl : 'partials/realm-ldap.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'RealmSMTPSettingsCtrl'
|
||||||
|
})
|
||||||
.when('/create/user/:realm', {
|
.when('/create/user/:realm', {
|
||||||
templateUrl : 'partials/user-detail.html',
|
templateUrl : 'partials/user-detail.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||||
|
<div id="content-area" class="col-sm-9" role="main">
|
||||||
|
<data-kc-navigation data-kc-current="ldap" data-kc-realm="realm.realm" data-kc-social="realm.social"></data-kc-navigation>
|
||||||
|
<div id="content">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
|
||||||
|
<li class="active">Ldap Configuration</li>
|
||||||
|
</ol>
|
||||||
|
<h2><span>{{realm.realm}}</span> Email Server Settings</h2>
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
|
||||||
|
<fieldset>
|
||||||
|
<legend><span class="text">Required Settings</span></legend>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpHost">Host <span class="required">*</span></label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="smtpHost" type="text" ng-model="realm.smtpServer.host" placeholder="SMTP Host" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpPort">Port <span class="required">*</span></label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="smtpPort" type="number" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpFrom">From <span class="required">*</span></label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="Sender Email Address" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpSSL">Enable SSL</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="realm.smtpServer.ssl" name="smtpSSL" id="smtpSSL" onoffswitch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpStartTLS">Enable StartTLS</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="realm.smtpServer.starttls" name="smtpStartTLS" id="smtpStartTLS" onoffswitch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend><span class="text">Authentication</span></legend>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpAuth">Enable Authentication</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="realm.smtpServer.auth" name="smtpAuth" id="smtpAuth" onoffswitch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpUsername">Username <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="Login Username" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
|
||||||
|
<label class="col-sm-2 control-label" for="smtpPassword">Password <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="Login Password" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||||
|
<button data-kc-reset data-ng-show="changed">Clear changes</button>
|
||||||
|
<button data-kc-save data-ng-show="changed">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -7,4 +7,5 @@
|
||||||
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
|
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
|
||||||
<li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
|
<li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
|
||||||
<li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
|
<li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
|
||||||
|
<li ng-class="{active: path[2] == 'ldap-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/ldap-settings">Ldap</a></li>
|
||||||
</ul>
|
</ul>
|
|
@ -13,7 +13,9 @@ import javax.ws.rs.core.MultivaluedMap;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.models.AuthenticationLinkModel;
|
import org.keycloak.models.AuthenticationLinkModel;
|
||||||
import org.keycloak.models.AuthenticationProviderModel;
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -30,6 +32,7 @@ import org.keycloak.spi.authentication.AuthenticationProviderManager;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class AuthProvidersExternalModelTest extends AbstractModelTest {
|
public class AuthProvidersExternalModelTest extends AbstractModelTest {
|
||||||
|
|
||||||
private RealmModel realm1;
|
private RealmModel realm1;
|
||||||
|
@ -63,14 +66,14 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExternalModelPasswordValidation() {
|
public void testExternalModelAuthentication() {
|
||||||
MultivaluedMap<String, String> formData = createFormData("john", "password");
|
MultivaluedMap<String, String> formData = createFormData("john", "password");
|
||||||
|
|
||||||
// Authenticate user with realm1
|
// Authenticate user with realm1
|
||||||
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(realm1, formData));
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(realm1, formData));
|
||||||
|
|
||||||
// Verify that user doesn't exists in realm2 and can't authenticate here
|
// Verify that user doesn't exists in realm2 and can't authenticate here
|
||||||
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(realm2, formData));
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(realm2, formData));
|
||||||
Assert.assertNull(realm2.getUser("john"));
|
Assert.assertNull(realm2.getUser("john"));
|
||||||
|
|
||||||
// Add externalModel authenticationProvider into realm2 and point to realm1
|
// Add externalModel authenticationProvider into realm2 and point to realm1
|
||||||
|
|
|
@ -10,10 +10,13 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.models.AuthenticationLinkModel;
|
import org.keycloak.models.AuthenticationLinkModel;
|
||||||
import org.keycloak.models.AuthenticationProviderModel;
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
@ -25,6 +28,7 @@ import org.keycloak.util.KeycloakRegistry;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class AuthProvidersLDAPTest extends AbstractModelTest {
|
public class AuthProvidersLDAPTest extends AbstractModelTest {
|
||||||
|
|
||||||
private RealmModel realm;
|
private RealmModel realm;
|
||||||
|
@ -64,11 +68,11 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLdapPasswordValidation() {
|
public void testLdapAuthentication() {
|
||||||
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password");
|
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password");
|
||||||
|
|
||||||
// Verify that user doesn't exists in realm2 and can't authenticate here
|
// Verify that user doesn't exists in realm2 and can't authenticate here
|
||||||
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(realm, formData));
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(realm, formData));
|
||||||
Assert.assertNull(realm.getUser("john"));
|
Assert.assertNull(realm.getUser("john"));
|
||||||
|
|
||||||
// Add ldap authenticationProvider
|
// Add ldap authenticationProvider
|
||||||
|
@ -87,9 +91,6 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
|
||||||
Assert.assertEquals("Doe", john.getLastName());
|
Assert.assertEquals("Doe", john.getLastName());
|
||||||
Assert.assertEquals("john@email.org", john.getEmail());
|
Assert.assertEquals("john@email.org", john.getEmail());
|
||||||
|
|
||||||
formData = AuthProvidersExternalModelTest.createFormData("john", "invalid");
|
|
||||||
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(realm, formData));
|
|
||||||
|
|
||||||
// Verify link exists
|
// Verify link exists
|
||||||
Set<AuthenticationLinkModel> authLinks = realm.getAuthenticationLinks(john);
|
Set<AuthenticationLinkModel> authLinks = realm.getAuthenticationLinks(john);
|
||||||
Assert.assertEquals(1, authLinks.size());
|
Assert.assertEquals(1, authLinks.size());
|
||||||
|
@ -101,6 +102,41 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLdapInvalidAuthentication() {
|
||||||
|
setupAuthenticationProviders();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, new KeycloakRegistry());
|
||||||
|
|
||||||
|
// Add some user and password to realm
|
||||||
|
UserModel realmUser = realm.addUser("realmUser");
|
||||||
|
UserCredentialModel credential = new UserCredentialModel();
|
||||||
|
credential.setType(CredentialRepresentation.PASSWORD);
|
||||||
|
credential.setValue("pass");
|
||||||
|
realm.updateCredential(realmUser, credential);
|
||||||
|
|
||||||
|
// User doesn't exists
|
||||||
|
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("invalid", "invalid");
|
||||||
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(realm, formData));
|
||||||
|
|
||||||
|
// User exists in ldap
|
||||||
|
formData = AuthProvidersExternalModelTest.createFormData("john", "invalid");
|
||||||
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(realm, formData));
|
||||||
|
|
||||||
|
// User exists in realm
|
||||||
|
formData = AuthProvidersExternalModelTest.createFormData("realmUser", "invalid");
|
||||||
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(realm, formData));
|
||||||
|
|
||||||
|
// User disabled
|
||||||
|
realmUser.setEnabled(false);
|
||||||
|
formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass");
|
||||||
|
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.ACCOUNT_DISABLED, am.authenticateForm(realm, formData));
|
||||||
|
} finally {
|
||||||
|
ResteasyProviderFactory.clearContextData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLdapPasswordUpdate() {
|
public void testLdapPasswordUpdate() {
|
||||||
// Add ldap
|
// Add ldap
|
||||||
|
|
|
@ -224,9 +224,12 @@ public class AuthenticationManager {
|
||||||
logger.debug("validating password for user: " + username);
|
logger.debug("validating password for user: " + username);
|
||||||
|
|
||||||
AuthResult authResult = AuthenticationProviderManager.getManager(realm).validatePassword(username, password);
|
AuthResult authResult = AuthenticationProviderManager.getManager(realm).validatePassword(username, password);
|
||||||
if (authResult.getAuthProviderStatus() == AuthProviderStatus.FAILED) {
|
if (authResult.getAuthProviderStatus() == AuthProviderStatus.INVALID_CREDENTIALS) {
|
||||||
logger.debug("invalid password for user: " + username);
|
logger.debug("invalid password for user: " + username);
|
||||||
return AuthenticationStatus.INVALID_CREDENTIALS;
|
return AuthenticationStatus.INVALID_CREDENTIALS;
|
||||||
|
} else if (authResult.getAuthProviderStatus() == AuthProviderStatus.USER_NOT_FOUND) {
|
||||||
|
logger.debug("User " + username + " not found in any Authentication provider");
|
||||||
|
return AuthenticationStatus.INVALID_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authResult.getAuthenticatedUser() != null) {
|
if (authResult.getAuthenticatedUser() != null) {
|
||||||
|
|
|
@ -29,14 +29,13 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
|
||||||
|
|
||||||
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
||||||
|
|
||||||
// Ignore if user doesn't exists, so that other providers have opportunity to authenticate (and possibly create) him
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return new AuthResult(AuthProviderStatus.IGNORE);
|
return new AuthResult(AuthProviderStatus.USER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result = realm.validatePassword(user, password);
|
boolean result = realm.validatePassword(user, password);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return new AuthResult(AuthProviderStatus.IGNORE);
|
return new AuthResult(AuthProviderStatus.INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticatedUser authUser = createAuthenticatedUserInstance(user);
|
AuthenticatedUser authUser = createAuthenticatedUserInstance(user);
|
||||||
|
|
|
@ -39,23 +39,26 @@ public class PicketlinkAuthenticationProvider implements AuthenticationProvider
|
||||||
public AuthResult validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
public AuthResult validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
||||||
IdentityManager identityManager = getIdentityManager(realm);
|
IdentityManager identityManager = getIdentityManager(realm);
|
||||||
|
|
||||||
|
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
||||||
|
if (picketlinkUser == null) {
|
||||||
|
return new AuthResult(AuthProviderStatus.USER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
||||||
credential.setUsername(username);
|
credential.setUsername(username);
|
||||||
credential.setPassword(new Password(password.toCharArray()));
|
credential.setPassword(new Password(password.toCharArray()));
|
||||||
identityManager.validateCredentials(credential);
|
identityManager.validateCredentials(credential);
|
||||||
|
|
||||||
AuthResult result;
|
|
||||||
if (credential.getStatus() == Credentials.Status.VALID) {
|
if (credential.getStatus() == Credentials.Status.VALID) {
|
||||||
result = new AuthResult(AuthProviderStatus.SUCCESS);
|
AuthResult result = new AuthResult(AuthProviderStatus.SUCCESS);
|
||||||
|
|
||||||
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
|
||||||
AuthenticatedUser authenticatedUser = new AuthenticatedUser(picketlinkUser.getId(), picketlinkUser.getLoginName())
|
AuthenticatedUser authenticatedUser = new AuthenticatedUser(picketlinkUser.getId(), picketlinkUser.getLoginName())
|
||||||
.setName(picketlinkUser.getFirstName(), picketlinkUser.getLastName())
|
.setName(picketlinkUser.getFirstName(), picketlinkUser.getLastName())
|
||||||
.setEmail(picketlinkUser.getEmail());
|
.setEmail(picketlinkUser.getEmail());
|
||||||
result.setUser(authenticatedUser).setProviderName(getName());
|
result.setUser(authenticatedUser).setProviderName(getName());
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
return new AuthResult(AuthProviderStatus.IGNORE);
|
return new AuthResult(AuthProviderStatus.INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,6 @@ package org.keycloak.spi.authentication;
|
||||||
*/
|
*/
|
||||||
public enum AuthProviderStatus {
|
public enum AuthProviderStatus {
|
||||||
|
|
||||||
// Ignore means that AuthenticationProvider wasn't able to authenticate result, but it should postpone authentication to next provider (for example user didn't exists in realm)
|
SUCCESS, INVALID_CREDENTIALS, USER_NOT_FOUND
|
||||||
SUCCESS, FAILED, IGNORE
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ public interface AuthenticationProvider {
|
||||||
*
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* @param password
|
* @param password
|
||||||
* @return
|
* @return result of authentication, which might eventually encapsulate info about authenticated user and provider which successfully authenticated
|
||||||
*/
|
*/
|
||||||
AuthResult validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
AuthResult validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import org.keycloak.util.ProviderLoader;
|
||||||
*
|
*
|
||||||
* Example of usage: AuthenticationProviderManager.getManager(realm).validateUser("joe", "password");
|
* Example of usage: AuthenticationProviderManager.getManager(realm).validateUser("joe", "password");
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public class AuthenticationProviderManager {
|
public class AuthenticationProviderManager {
|
||||||
|
@ -50,6 +49,7 @@ public class AuthenticationProviderManager {
|
||||||
|
|
||||||
public AuthResult validatePassword(String username, String password) {
|
public AuthResult validatePassword(String username, String password) {
|
||||||
List<AuthenticationProviderModel> configuredProviders = getConfiguredProviders(realm);
|
List<AuthenticationProviderModel> configuredProviders = getConfiguredProviders(realm);
|
||||||
|
boolean userExists = false;
|
||||||
|
|
||||||
for (AuthenticationProviderModel authProviderConfig : configuredProviders) {
|
for (AuthenticationProviderModel authProviderConfig : configuredProviders) {
|
||||||
String providerName = authProviderConfig.getProviderName();
|
String providerName = authProviderConfig.getProviderName();
|
||||||
|
@ -63,17 +63,20 @@ public class AuthenticationProviderManager {
|
||||||
AuthResult currentResult = delegate.validatePassword(realm, authProviderConfig.getConfig(), username, password);
|
AuthResult currentResult = delegate.validatePassword(realm, authProviderConfig.getConfig(), username, password);
|
||||||
logger.debugf("Authentication provider '%s' finished with '%s' for authentication of '%s'", delegate.getName(), currentResult.getAuthProviderStatus().toString(), username);
|
logger.debugf("Authentication provider '%s' finished with '%s' for authentication of '%s'", delegate.getName(), currentResult.getAuthProviderStatus().toString(), username);
|
||||||
|
|
||||||
if (currentResult.getAuthProviderStatus() == AuthProviderStatus.SUCCESS || currentResult.getAuthProviderStatus() == AuthProviderStatus.FAILED) {
|
if (currentResult.getAuthProviderStatus() == AuthProviderStatus.SUCCESS) {
|
||||||
return currentResult;
|
return currentResult;
|
||||||
|
} else if (currentResult.getAuthProviderStatus() == AuthProviderStatus.INVALID_CREDENTIALS) {
|
||||||
|
userExists = true;
|
||||||
}
|
}
|
||||||
} catch (AuthenticationProviderException ape) {
|
} catch (AuthenticationProviderException ape) {
|
||||||
logger.warn(ape.getMessage(), ape);
|
logger.warn(ape.getMessage(), ape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debugf("Not able to authenticate '%s' with any authentication provider", username);
|
AuthProviderStatus status = userExists ? AuthProviderStatus.INVALID_CREDENTIALS : AuthProviderStatus.USER_NOT_FOUND;
|
||||||
|
logger.debugf("Not able to authenticate '%s' with any authentication provider. Status: '%s'", username, status.toString());
|
||||||
|
|
||||||
return new AuthResult(AuthProviderStatus.FAILED);
|
return new AuthResult(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePassword(String username, String password) throws AuthenticationProviderException {
|
public void updatePassword(String username, String password) throws AuthenticationProviderException {
|
||||||
|
@ -97,7 +100,7 @@ public class AuthenticationProviderManager {
|
||||||
}
|
}
|
||||||
} catch (AuthenticationProviderException ape) {
|
} catch (AuthenticationProviderException ape) {
|
||||||
// Rethrow it to upper layer
|
// Rethrow it to upper layer
|
||||||
logger.warn("Failed to update password", ape);
|
logger.warn("Failed to update password: " + ape.getMessage());
|
||||||
throw ape;
|
throw ape;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue