revactor CredentialValidationOutput apis

This commit is contained in:
Bill Burke 2016-10-04 17:26:45 -04:00
parent 4af0976194
commit c5600e888d
12 changed files with 64 additions and 99 deletions

View file

@ -637,11 +637,6 @@ public class UserCacheSession implements UserCache {
return getDelegate().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
return getDelegate().validCredentials(session, realm, input);
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
realmInvalidations.add(realm.getId()); // easier to just invalidate whole realm

View file

@ -707,12 +707,6 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
return (entity != null) ? new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken()) : null;
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
// Not supported yet
return null;
}
@Override
public void preRemove(RealmModel realm, ComponentModel component) {

View file

@ -517,12 +517,6 @@ public class MongoUserProvider implements UserProvider, UserCredentialStore {
getMongoStore().updateEntities(MongoUserConsentEntity.class, query, pull, invocationContext);
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
// Not supported yet
return null;
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();

View file

@ -14,20 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.storage.user;
package org.keycloak.credential;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import java.util.Set;
/**
* Single purpose method that knows how to authenticate a user based on a credential type. This is used when the user
* is not known but the provider knows how to extract this information from the credential. Examples are Kerberos.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserCredentialAuthenticationProvider {
Set<String> getSupportedCredentialAuthenticationTypes();
CredentialValidationOutput validCredential(KeycloakSession session, RealmModel realm, UserCredentialModel input);
public interface CredentialAuthentication {
boolean supportsCredentialAuthenticationFor(String type);
CredentialValidationOutput authenticate(RealmModel realm, CredentialInput input);
}

View file

@ -49,6 +49,11 @@ public class CredentialValidationOutput {
return authStatus;
}
/**
* State that is passed back by provider
*
* @return
*/
public Map<String, String> getState() {
return state;
}

View file

@ -90,4 +90,17 @@ public interface UserCredentialManager extends UserCredentialStore {
* @return
*/
boolean isConfiguredLocally(RealmModel realm, UserModel user, String type);
/**
* Given a CredentialInput, authenticate the user. This is used in the case where the credential must be processed
* to determine and find the user. An example is Kerberos where the kerberos token might be validated and processed
* by a variety of different storage providers.
*
*
* @param session
* @param realm
* @param input
* @return
*/
CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input);
}

View file

@ -73,7 +73,7 @@ public class UserFederationManager implements UserProvider {
return user;
}
protected UserFederationProvider getFederationProvider(UserFederationProviderModel model) {
public UserFederationProvider getFederationProvider(UserFederationProviderModel model) {
return KeycloakModelUtils.getFederationProviderInstance(session, model);
}
@ -484,40 +484,6 @@ public class UserFederationManager implements UserProvider {
session.userStorage().preRemove(protocolMapper);
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
List<UserFederationProvider> fedProviders = new ArrayList<UserFederationProvider>();
for (UserFederationProviderModel fedProviderModel : fedProviderModels) {
fedProviders.add(getFederationProvider(fedProviderModel));
}
CredentialValidationOutput result = null;
for (UserCredentialModel cred : input) {
UserFederationProvider providerSupportingCreds = null;
// Find first provider, which supports required credential type
for (UserFederationProvider fedProvider : fedProviders) {
if (fedProvider.getSupportedCredentialTypes().contains(cred.getType())) {
providerSupportingCreds = fedProvider;
break;
}
}
if (providerSupportingCreds == null) {
logger.warn("Don't have provider supporting credentials of type " + cred.getType());
return CredentialValidationOutput.failed();
}
logger.debug("Found provider [" + providerSupportingCreds + "] supporting credentials of type " + cred.getType());
CredentialValidationOutput currentResult = providerSupportingCreds.validCredentials(realm, cred);
result = (result == null) ? currentResult : result.merge(currentResult);
}
// For now, validCredentials(realm, input) is not supported for local userProviders
return (result != null) ? result : CredentialValidationOutput.failed();
}
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
session.userStorage().preRemove(realm, component);

View file

@ -75,10 +75,6 @@ public interface UserProvider extends Provider,
void preRemove(RealmModel realm, ClientModel client);
void preRemove(ProtocolMapperModel protocolMapper);
CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input);
void close();
void preRemove(RealmModel realm, ComponentModel component);

View file

@ -86,7 +86,7 @@ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator imple
String spnegoToken = tokens[1];
UserCredentialModel spnegoCredential = UserCredentialModel.kerberos(spnegoToken);
CredentialValidationOutput output = context.getSession().users().validCredentials(context.getSession(), context.getRealm(), spnegoCredential);
CredentialValidationOutput output = context.getSession().userCredentialManager().authenticate(context.getSession(), context.getRealm(), spnegoCredential);
if (output.getAuthStatus() == CredentialValidationOutput.Status.AUTHENTICATED) {
context.setUser(output.getAuthenticatedUser());

View file

@ -17,18 +17,23 @@
package org.keycloak.credential;
import org.keycloak.common.util.reflections.Types;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialManager;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.cache.OnUserCache;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageManager;
import org.keycloak.storage.UserStorageProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
@ -246,6 +251,37 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
return false;
}
@Override
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
List<UserFederationProvider> fedProviders = new ArrayList<UserFederationProvider>();
for (UserFederationProviderModel fedProviderModel : fedProviderModels) {
UserFederationProvider provider = session.users().getFederationProvider(fedProviderModel);
if (input instanceof UserCredentialModel && provider != null && provider.supportsCredentialType(input.getType())) {
CredentialValidationOutput output = provider.validCredentials(realm, (UserCredentialModel)input);
if (output != null) return output;
}
}
List<CredentialAuthentication> list = UserStorageManager.getStorageProviders(session, realm, CredentialAuthentication.class);
for (CredentialAuthentication auth : list) {
if (auth.supportsCredentialAuthenticationFor(input.getType())) {
CredentialValidationOutput output = auth.authenticate(realm, input);
if (output != null) return output;
}
}
list = getCredentialProviders(realm, CredentialAuthentication.class);
for (CredentialAuthentication auth : list) {
if (auth.supportsCredentialAuthenticationFor(input.getType())) {
CredentialValidationOutput output = auth.authenticate(realm, input);
if (output != null) return output;
}
}
return null;
}
@Override
public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
List<OnUserCache> credentialProviders = getCredentialProviders(realm, OnUserCache.class);

View file

@ -37,7 +37,7 @@ import org.keycloak.models.UserProvider;
import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.cache.OnUserCache;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.user.UserCredentialAuthenticationProvider;
import org.keycloak.credential.CredentialAuthentication;
import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
@ -528,37 +528,6 @@ public class UserStorageManager implements UserProvider, OnUserCache {
if (getFederatedStorage() != null) getFederatedStorage().preRemove(protocolMapper);
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
List<UserCredentialAuthenticationProvider> providers = getStorageProviders(session, realm, UserCredentialAuthenticationProvider.class);
if (providers.isEmpty()) return CredentialValidationOutput.failed();
CredentialValidationOutput result = null;
for (UserCredentialModel cred : input) {
UserCredentialAuthenticationProvider providerSupportingCreds = null;
// Find first provider, which supports required credential type
for (UserCredentialAuthenticationProvider provider : providers) {
if (provider.getSupportedCredentialAuthenticationTypes().contains(cred.getType())) {
providerSupportingCreds = provider;
break;
}
}
if (providerSupportingCreds == null) {
logger.warn("Don't have provider supporting credentials of type " + cred.getType());
return CredentialValidationOutput.failed();
}
logger.debug("Found provider [" + providerSupportingCreds + "] supporting credentials of type " + cred.getType());
CredentialValidationOutput currentResult = providerSupportingCreds.validCredential(session, realm, cred);
result = (result == null) ? currentResult : result.merge(currentResult);
}
// For now, validCredentials(realm, input) is not supported for local userProviders
return (result != null) ? result : CredentialValidationOutput.failed();
}
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
if (!component.getProviderType().equals(UserStorageProvider.class.getName())) return;

View file

@ -22,20 +22,17 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.authentication.AuthenticationFlow;
import org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory;
import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.storage.user.UserCredentialAuthenticationProvider;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.ExecutionBuilder;
@ -45,8 +42,6 @@ import org.keycloak.testsuite.util.UserBuilder;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
/**
* Tests for {@link org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator}