Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
95349e6
commit 3dd282e
Showing
11 changed files
with
482 additions
and
42 deletions.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
services/src/main/java/org/keycloak/authentication/RequiredActionFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.keycloak.authentication; | ||
|
||
import org.keycloak.provider.ProviderFactory; | ||
|
||
/** | ||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> | ||
* @version $Revision: 1 $ | ||
*/ | ||
public interface RequiredActionFactory extends ProviderFactory<RequiredActionProvider> { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
services/src/main/java/org/keycloak/authentication/RequiredActionSpi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.keycloak.authentication; | ||
|
||
import org.keycloak.provider.Provider; | ||
import org.keycloak.provider.ProviderFactory; | ||
import org.keycloak.provider.Spi; | ||
|
||
/** | ||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> | ||
*/ | ||
public class RequiredActionSpi implements Spi { | ||
|
||
@Override | ||
public boolean isInternal() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "required-action"; | ||
} | ||
|
||
@Override | ||
public Class<? extends Provider> getProviderClass() { | ||
return RequiredActionProvider.class; | ||
} | ||
|
||
@Override | ||
public Class<? extends ProviderFactory> getProviderFactoryClass() { | ||
return RequiredActionFactory.class; | ||
} | ||
|
||
} |
93 changes: 93 additions & 0 deletions
93
services/src/main/java/org/keycloak/authentication/actions/UpdatePassword.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package org.keycloak.authentication.actions; | ||
|
||
import org.jboss.logging.Logger; | ||
import org.keycloak.Config; | ||
import org.keycloak.authentication.RequiredActionContext; | ||
import org.keycloak.authentication.RequiredActionFactory; | ||
import org.keycloak.authentication.RequiredActionProvider; | ||
import org.keycloak.login.LoginFormsProvider; | ||
import org.keycloak.models.ClientSessionModel; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.KeycloakSessionFactory; | ||
import org.keycloak.models.UserCredentialModel; | ||
import org.keycloak.models.UserCredentialValueModel; | ||
import org.keycloak.models.UserModel; | ||
import org.keycloak.services.managers.ClientSessionCode; | ||
import org.keycloak.util.Time; | ||
|
||
import javax.ws.rs.core.Response; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> | ||
* @version $Revision: 1 $ | ||
*/ | ||
public class UpdatePassword implements RequiredActionProvider, RequiredActionFactory { | ||
protected static Logger logger = Logger.getLogger(UpdatePassword.class); | ||
@Override | ||
public void evaluateTriggers(RequiredActionContext context) { | ||
int daysToExpirePassword = context.getRealm().getPasswordPolicy().getDaysToExpirePassword(); | ||
if(daysToExpirePassword != -1) { | ||
for (UserCredentialValueModel entity : context.getUser().getCredentialsDirectly()) { | ||
if (entity.getType().equals(UserCredentialModel.PASSWORD)) { | ||
|
||
if(entity.getCreatedDate() == null) { | ||
context.getUser().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); | ||
logger.debug("User is required to update password"); | ||
} else { | ||
long timeElapsed = Time.toMillis(Time.currentTime()) - entity.getCreatedDate(); | ||
long timeToExpire = TimeUnit.DAYS.toMillis(daysToExpirePassword); | ||
|
||
if(timeElapsed > timeToExpire) { | ||
context.getUser().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); | ||
logger.debug("User is required to update password"); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public Response invokeRequiredAction(RequiredActionContext context) { | ||
ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession()); | ||
accessCode.setAction(ClientSessionModel.Action.UPDATE_PASSWORD.name()); | ||
|
||
LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode()) | ||
.setUser(context.getUser()); | ||
return loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); | ||
} | ||
|
||
@Override | ||
public Object jaxrsService(RequiredActionContext context) { | ||
// this is handled by LoginActionsService at the moment | ||
return null; | ||
} | ||
|
||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
|
||
@Override | ||
public RequiredActionProvider create(KeycloakSession session) { | ||
return this; | ||
} | ||
|
||
@Override | ||
public void init(Config.Scope config) { | ||
|
||
} | ||
|
||
@Override | ||
public void postInit(KeycloakSessionFactory factory) { | ||
|
||
} | ||
|
||
@Override | ||
public String getId() { | ||
return UserModel.RequiredAction.UPDATE_PASSWORD.name(); | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
services/src/main/java/org/keycloak/authentication/actions/UpdateProfile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package org.keycloak.authentication.actions; | ||
|
||
import org.jboss.logging.Logger; | ||
import org.keycloak.Config; | ||
import org.keycloak.authentication.RequiredActionContext; | ||
import org.keycloak.authentication.RequiredActionFactory; | ||
import org.keycloak.authentication.RequiredActionProvider; | ||
import org.keycloak.login.LoginFormsProvider; | ||
import org.keycloak.models.ClientSessionModel; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.KeycloakSessionFactory; | ||
import org.keycloak.models.RequiredCredentialModel; | ||
import org.keycloak.models.UserModel; | ||
import org.keycloak.representations.idm.CredentialRepresentation; | ||
import org.keycloak.services.managers.ClientSessionCode; | ||
|
||
import javax.ws.rs.core.Response; | ||
|
||
/** | ||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> | ||
* @version $Revision: 1 $ | ||
*/ | ||
public class UpdateProfile implements RequiredActionProvider, RequiredActionFactory { | ||
protected static Logger logger = Logger.getLogger(UpdateProfile.class); | ||
@Override | ||
public void evaluateTriggers(RequiredActionContext context) { | ||
if (context.getRealm().isVerifyEmail() && !context.getUser().isEmailVerified()) { | ||
context.getUser().addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); | ||
logger.debug("User is required to verify email"); | ||
} | ||
} | ||
|
||
@Override | ||
public Response invokeRequiredAction(RequiredActionContext context) { | ||
ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession()); | ||
accessCode.setAction(ClientSessionModel.Action.UPDATE_PROFILE.name()); | ||
|
||
LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode()) | ||
.setUser(context.getUser()); | ||
return loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PROFILE); | ||
} | ||
|
||
@Override | ||
public Object jaxrsService(RequiredActionContext context) { | ||
// this is handled by LoginActionsService at the moment | ||
// todo should be refactored to contain it here | ||
return null; | ||
} | ||
|
||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
|
||
@Override | ||
public RequiredActionProvider create(KeycloakSession session) { | ||
return this; | ||
} | ||
|
||
@Override | ||
public void init(Config.Scope config) { | ||
|
||
} | ||
|
||
@Override | ||
public void postInit(KeycloakSessionFactory factory) { | ||
|
||
} | ||
|
||
@Override | ||
public String getId() { | ||
return UserModel.RequiredAction.UPDATE_PROFILE.name(); | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
services/src/main/java/org/keycloak/authentication/actions/UpdateTotp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package org.keycloak.authentication.actions; | ||
|
||
import org.jboss.logging.Logger; | ||
import org.keycloak.Config; | ||
import org.keycloak.authentication.RequiredActionContext; | ||
import org.keycloak.authentication.RequiredActionFactory; | ||
import org.keycloak.authentication.RequiredActionProvider; | ||
import org.keycloak.login.LoginFormsProvider; | ||
import org.keycloak.models.ClientSessionModel; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.KeycloakSessionFactory; | ||
import org.keycloak.models.RequiredCredentialModel; | ||
import org.keycloak.models.UserCredentialModel; | ||
import org.keycloak.models.UserCredentialValueModel; | ||
import org.keycloak.models.UserModel; | ||
import org.keycloak.representations.idm.CredentialRepresentation; | ||
import org.keycloak.services.managers.ClientSessionCode; | ||
import org.keycloak.util.Time; | ||
|
||
import javax.ws.rs.core.Response; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> | ||
* @version $Revision: 1 $ | ||
*/ | ||
public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory { | ||
protected static Logger logger = Logger.getLogger(UpdateTotp.class); | ||
@Override | ||
public void evaluateTriggers(RequiredActionContext context) { | ||
// I don't think we need this check here. AuthenticationProcessor should be setting the required action | ||
// if OTP changes from required from optional or disabled | ||
for (RequiredCredentialModel c : context.getRealm().getRequiredCredentials()) { | ||
if (c.getType().equals(CredentialRepresentation.TOTP) && !context.getUser().isTotp()) { | ||
context.getUser().addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP); | ||
logger.debug("User is required to configure totp"); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public Response invokeRequiredAction(RequiredActionContext context) { | ||
ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession()); | ||
accessCode.setAction(ClientSessionModel.Action.CONFIGURE_TOTP.name()); | ||
|
||
LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode()) | ||
.setUser(context.getUser()); | ||
return loginFormsProvider.createResponse(UserModel.RequiredAction.CONFIGURE_TOTP); | ||
} | ||
|
||
@Override | ||
public Object jaxrsService(RequiredActionContext context) { | ||
// this is handled by LoginActionsService at the moment | ||
// todo should be refactored to contain it here | ||
return null; | ||
} | ||
|
||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
|
||
@Override | ||
public RequiredActionProvider create(KeycloakSession session) { | ||
return this; | ||
} | ||
|
||
@Override | ||
public void init(Config.Scope config) { | ||
|
||
} | ||
|
||
@Override | ||
public void postInit(KeycloakSessionFactory factory) { | ||
|
||
} | ||
|
||
@Override | ||
public String getId() { | ||
return UserModel.RequiredAction.CONFIGURE_TOTP.name(); | ||
} | ||
|
||
} |
Oops, something went wrong.