Skip to content

Commit

Permalink
credential refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
patriot1burke committed Sep 22, 2016
1 parent 84f5c09 commit 7209a95
Show file tree
Hide file tree
Showing 106 changed files with 1,579 additions and 1,368 deletions.
Expand Up @@ -17,6 +17,10 @@


package org.keycloak.representations.idm; package org.keycloak.representations.idm;


import org.keycloak.common.util.MultivaluedHashMap;

import java.util.Map;

/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
Expand Down Expand Up @@ -45,6 +49,7 @@ public class CredentialRepresentation {
private Integer digits; private Integer digits;
private Integer period; private Integer period;
private Long createdDate; private Long createdDate;
private MultivaluedHashMap<String, String> config;


// only used when updating a credential. Might set required action // only used when updating a credential. Might set required action
protected Boolean temporary; protected Boolean temporary;
Expand Down Expand Up @@ -144,4 +149,12 @@ public Long getCreatedDate() {
public void setCreatedDate(Long createdDate) { public void setCreatedDate(Long createdDate) {
this.createdDate = createdDate; this.createdDate = createdDate;
} }

public MultivaluedHashMap<String, String> getConfig() {
return config;
}

public void setConfig(MultivaluedHashMap<String, String> config) {
this.config = config;
}
} }
10 changes: 10 additions & 0 deletions examples/providers/authenticator/pom.xml
Expand Up @@ -55,5 +55,15 @@


<build> <build>
<finalName>authenticator-required-action-example</finalName> <finalName>authenticator-required-action-example</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build> </build>
</project> </project>
Expand Up @@ -23,6 +23,7 @@
import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.services.util.CookieHelper; import org.keycloak.services.util.CookieHelper;
Expand Down Expand Up @@ -96,15 +97,10 @@ protected void setCookie(AuthenticationFlowContext context) {
protected boolean validateAnswer(AuthenticationFlowContext context) { protected boolean validateAnswer(AuthenticationFlowContext context) {
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters(); MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
String secret = formData.getFirst("secret_answer"); String secret = formData.getFirst("secret_answer");
UserCredentialValueModel cred = null; UserCredentialModel input = new UserCredentialModel();
for (UserCredentialValueModel model : context.getUser().getCredentialsDirectly()) { input.setType(SecretQuestionCredentialProvider.SECRET_QUESTION);
if (model.getType().equals(CREDENTIAL_TYPE)) { input.setValue(secret);
cred = model; return context.getSession().userCredentialManager().isValid(context.getRealm(), context.getUser(), input);
break;
}
}

return cred.getValue().equals(secret);
} }


@Override @Override
Expand All @@ -114,7 +110,7 @@ public boolean requiresUser() {


@Override @Override
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
return session.users().configuredForCredentialType(CREDENTIAL_TYPE, realm, user); return session.userCredentialManager().isConfiguredFor(realm, user, SecretQuestionCredentialProvider.SECRET_QUESTION);
} }


@Override @Override
Expand Down
@@ -0,0 +1,117 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.examples.authenticator;

import org.keycloak.common.util.Time;
import org.keycloak.credential.CredentialInput;
import org.keycloak.credential.CredentialInputUpdater;
import org.keycloak.credential.CredentialInputValidator;
import org.keycloak.credential.CredentialModel;
import org.keycloak.credential.CredentialProvider;
import org.keycloak.credential.PasswordCredentialProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.cache.OnUserCache;

import java.util.List;

/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SecretQuestionCredentialProvider implements CredentialProvider, CredentialInputValidator, CredentialInputUpdater, OnUserCache {
public static final String SECRET_QUESTION = "SECRET_QUESTION";
public static final String CACHE_KEY = SecretQuestionCredentialProvider.class.getName() + "." + SECRET_QUESTION;

protected KeycloakSession session;

public SecretQuestionCredentialProvider(KeycloakSession session) {
this.session = session;
}

public CredentialModel getSecret(RealmModel realm, UserModel user) {
CredentialModel secret = null;
if (user instanceof CachedUserModel) {
CachedUserModel cached = (CachedUserModel)user;
secret = (CredentialModel)cached.getCachedWith().get(CACHE_KEY);

} else {
List<CredentialModel> creds = session.userCredentialManager().getStoredCredentialsByType(realm, user, SECRET_QUESTION);
if (!creds.isEmpty()) secret = creds.get(0);
}
return secret;
}


@Override
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
if (!SECRET_QUESTION.equals(input.getType())) return false;
if (!(input instanceof UserCredentialModel)) return false;
UserCredentialModel credInput = (UserCredentialModel) input;
List<CredentialModel> creds = session.userCredentialManager().getStoredCredentialsByType(realm, user, SECRET_QUESTION);
if (creds.isEmpty()) {
CredentialModel secret = new CredentialModel();
secret.setType(SECRET_QUESTION);
secret.setValue(credInput.getValue());
secret.setCreatedDate(Time.toMillis(Time.currentTime()));
session.userCredentialManager().createCredential(realm ,user, secret);
} else {
creds.get(0).setValue(credInput.getValue());
session.userCredentialManager().updateCredential(realm, user, creds.get(0));
}
session.getUserCache().evict(realm, user);
return true;
}

@Override
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
if (!SECRET_QUESTION.equals(credentialType)) return;
session.userCredentialManager().disableCredential(realm, user, credentialType);
session.getUserCache().evict(realm, user);

}

@Override
public boolean supportsCredentialType(String credentialType) {
return SECRET_QUESTION.equals(credentialType);
}

@Override
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
if (!SECRET_QUESTION.equals(credentialType)) return false;
return getSecret(realm, user) != null;
}

@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
if (!SECRET_QUESTION.equals(input.getType())) return false;
if (!(input instanceof UserCredentialModel)) return false;

String secret = getSecret(realm, user).getValue();

return secret != null && ((UserCredentialModel)input).getValue().equals(secret);
}

@Override
public void onCache(RealmModel realm, CachedUserModel user) {
List<CredentialModel> creds = session.userCredentialManager().getStoredCredentialsByType(realm, user, SECRET_QUESTION);
if (!creds.isEmpty()) user.getCachedWith().put(CACHE_KEY, creds.get(0));
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.examples.authenticator;

import org.keycloak.credential.CredentialProvider;
import org.keycloak.credential.CredentialProviderFactory;
import org.keycloak.models.KeycloakSession;

/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SecretQuestionCredentialProviderFactory implements CredentialProviderFactory<SecretQuestionCredentialProvider> {
@Override
public String getId() {
return "secret-question";
}

@Override
public CredentialProvider create(KeycloakSession session) {
return new SecretQuestionCredentialProvider(session);
}
}
Expand Up @@ -19,6 +19,7 @@


import org.keycloak.authentication.RequiredActionContext; import org.keycloak.authentication.RequiredActionContext;
import org.keycloak.authentication.RequiredActionProvider; import org.keycloak.authentication.RequiredActionProvider;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserCredentialValueModel;


import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
Expand All @@ -45,10 +46,10 @@ public void requiredActionChallenge(RequiredActionContext context) {
@Override @Override
public void processAction(RequiredActionContext context) { public void processAction(RequiredActionContext context) {
String answer = (context.getHttpRequest().getDecodedFormParameters().getFirst("secret_answer")); String answer = (context.getHttpRequest().getDecodedFormParameters().getFirst("secret_answer"));
UserCredentialValueModel model = new UserCredentialValueModel(); UserCredentialModel input = new UserCredentialModel();
model.setValue(answer); input.setType(SecretQuestionCredentialProvider.SECRET_QUESTION);
model.setType(SecretQuestionAuthenticator.CREDENTIAL_TYPE); input.setValue(answer);
context.getUser().updateCredentialDirectly(model); context.getSession().userCredentialManager().updateCredential(context.getRealm(), context.getUser(), input);
context.success(); context.success();
} }


Expand Down
@@ -0,0 +1 @@
org.keycloak.examples.authenticator.SecretQuestionCredentialProviderFactory
Expand Up @@ -17,6 +17,7 @@


package org.keycloak.examples.federation.properties; package org.keycloak.examples.federation.properties;


import org.keycloak.credential.CredentialInput;
import org.keycloak.models.CredentialValidationOutput; import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
Expand Down Expand Up @@ -146,48 +147,29 @@ public boolean isValid(RealmModel realm, UserModel local) {
return properties.containsKey(local.getUsername()); return properties.containsKey(local.getUsername());
} }


/**
* hardcoded to only return PASSWORD
*
* @param user
* @return
*/
@Override @Override
public Set<String> getSupportedCredentialTypes(UserModel user) { public Set<String> getSupportedCredentialTypes() {
return supportedCredentialTypes; return supportedCredentialTypes;
} }


@Override @Override
public Set<String> getSupportedCredentialTypes() { public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
return supportedCredentialTypes; if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;

UserCredentialModel cred = (UserCredentialModel)input;
String password = properties.getProperty(user.getUsername());
if (password == null) return false;
return password.equals(cred.getValue());
} }


@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) { public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
for (UserCredentialModel cred : input) { return getSupportedCredentialTypes().contains(credentialType);
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
String password = properties.getProperty(user.getUsername());
if (password == null) return false;
return password.equals(cred.getValue());
} else {
return false; // invalid cred type
}
}
return false;
} }


@Override @Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) { public boolean supportsCredentialType(String credentialType) {
for (UserCredentialModel cred : input) { return getSupportedCredentialTypes().contains(credentialType);
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
String password = properties.getProperty(user.getUsername());
if (password == null) return false;
return password.equals(cred.getValue());
} else {
return false; // invalid cred type
}
}
return true;
} }


@Override @Override
Expand Down
Expand Up @@ -17,8 +17,10 @@


package org.keycloak.examples.federation.properties; package org.keycloak.examples.federation.properties;


import org.keycloak.credential.CredentialInput;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;


Expand Down Expand Up @@ -80,6 +82,13 @@ public boolean removeUser(RealmModel realm, UserModel user) {
throw new IllegalStateException("Remove not supported"); throw new IllegalStateException("Remove not supported");
} }


@Override
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
return false;
}


@Override
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {


}
} }
Expand Up @@ -17,8 +17,10 @@


package org.keycloak.examples.federation.properties; package org.keycloak.examples.federation.properties;


import org.keycloak.credential.CredentialInput;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;


Expand Down Expand Up @@ -98,6 +100,13 @@ public boolean removeUser(RealmModel realm, UserModel user) {
} }
} }


@Override
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
return false;
}


@Override
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {


}
} }

0 comments on commit 7209a95

Please sign in to comment.