revactor CredentialValidationOutput apis
This commit is contained in:
parent
4af0976194
commit
c5600e888d
12 changed files with 64 additions and 99 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -49,6 +49,11 @@ public class CredentialValidationOutput {
|
|||
return authStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* State that is passed back by provider
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> getState() {
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in a new issue