clientsession.action to String
This commit is contained in:
parent
dcc40b0a63
commit
95349e6e2e
44 changed files with 989 additions and 561 deletions
|
@ -7,6 +7,13 @@
|
||||||
<delete tableName="CLIENT_SESSION"/>
|
<delete tableName="CLIENT_SESSION"/>
|
||||||
<delete tableName="USER_SESSION_NOTE"/>
|
<delete tableName="USER_SESSION_NOTE"/>
|
||||||
<delete tableName="USER_SESSION"/>
|
<delete tableName="USER_SESSION"/>
|
||||||
|
<createTable tableName="DEFAULT_REQUIRED_ACTIONS">
|
||||||
|
<column name="REALM_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="VALUE" type="VARCHAR(36)"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
<createTable tableName="ADMIN_EVENT_ENTITY">
|
<createTable tableName="ADMIN_EVENT_ENTITY">
|
||||||
<column name="ID" type="VARCHAR(36)">
|
<column name="ID" type="VARCHAR(36)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
|
@ -145,6 +152,63 @@
|
||||||
<column name="REQUIRED_ACTION" value="UPDATE_PASSWORD"/>
|
<column name="REQUIRED_ACTION" value="UPDATE_PASSWORD"/>
|
||||||
<where>ACTION = 3</where>
|
<where>ACTION = 3</where>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<addColumn tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<!-- OAUTH_GRANT,
|
||||||
|
CODE_TO_TOKEN,
|
||||||
|
VERIFY_EMAIL,
|
||||||
|
UPDATE_PROFILE,
|
||||||
|
CONFIGURE_TOTP,
|
||||||
|
UPDATE_PASSWORD,
|
||||||
|
RECOVER_PASSWORD,
|
||||||
|
AUTHENTICATE,
|
||||||
|
SOCIAL_CALLBACK,
|
||||||
|
LOGGED_OUT -->
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="OAUTH_GRANT"/>
|
||||||
|
<where>ACTION = 0</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="CODE_TO_TOKEN"/>
|
||||||
|
<where>ACTION = 1</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="VERIFY_EMAIL"/>
|
||||||
|
<where>ACTION = 2</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="UPDATE_PROFILE"/>
|
||||||
|
<where>ACTION = 3</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="CONFIGURE_TOTP"/>
|
||||||
|
<where>ACTION = 4</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="UPDATE_PASSWORD"/>
|
||||||
|
<where>ACTION = 5</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="RECOVER_PASSWORD"/>
|
||||||
|
<where>ACTION = 6</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="AUTHENTICATE"/>
|
||||||
|
<where>ACTION = 7</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="SOCIAL_CALLBACK"/>
|
||||||
|
<where>ACTION = 8</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="LOGGED_OUT"/>
|
||||||
|
<where>ACTION = 9</where>
|
||||||
|
</update>
|
||||||
|
|
||||||
<createTable tableName="CLIENT_USER_SESSION_NOTE">
|
<createTable tableName="CLIENT_USER_SESSION_NOTE">
|
||||||
<column name="NAME" type="VARCHAR(255)">
|
<column name="NAME" type="VARCHAR(255)">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
|
@ -162,10 +226,12 @@
|
||||||
<addPrimaryKey columnNames="AUTHENTICATOR_ID, NAME" constraintName="CONSTRAINT_AUTHENTICATOR_CONFIG_PK" tableName="AUTHENTICATOR_CONFIG"/>
|
<addPrimaryKey columnNames="AUTHENTICATOR_ID, NAME" constraintName="CONSTRAINT_AUTHENTICATOR_CONFIG_PK" tableName="AUTHENTICATOR_CONFIG"/>
|
||||||
<dropPrimaryKey constraintName="CONSTRAINT_2" tableName="USER_REQUIRED_ACTION"/>
|
<dropPrimaryKey constraintName="CONSTRAINT_2" tableName="USER_REQUIRED_ACTION"/>
|
||||||
<dropColumn tableName="USER_REQUIRED_ACTION" columnName="ACTION"/>
|
<dropColumn tableName="USER_REQUIRED_ACTION" columnName="ACTION"/>
|
||||||
|
<dropColumn tableName="CLIENT_SESSION" columnName="ACTION"/>
|
||||||
<addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTRAINT_REQUIRED_ACTION" tableName="USER_REQUIRED_ACTION"/>
|
<addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTRAINT_REQUIRED_ACTION" tableName="USER_REQUIRED_ACTION"/>
|
||||||
<addPrimaryKey columnNames="CLIENT_SESSION, AUTHENTICATOR" constraintName="CONSTRAINT_AUTH_STATUS_PK" tableName="CLIENT_SESSION_AUTH_STATUS"/>
|
<addPrimaryKey columnNames="CLIENT_SESSION, AUTHENTICATOR" constraintName="CONSTRAINT_AUTH_STATUS_PK" tableName="CLIENT_SESSION_AUTH_STATUS"/>
|
||||||
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FEDMAPPERPM" tableName="USER_FEDERATION_MAPPER"/>
|
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FEDMAPPERPM" tableName="USER_FEDERATION_MAPPER"/>
|
||||||
<addPrimaryKey columnNames="USER_FEDERATION_MAPPER_ID, NAME" constraintName="CONSTRAINT_FEDMAPPER_CFG_PM" tableName="USER_FEDERATION_MAPPER_CONFIG"/>
|
<addPrimaryKey columnNames="USER_FEDERATION_MAPPER_ID, NAME" constraintName="CONSTRAINT_FEDMAPPER_CFG_PM" tableName="USER_FEDERATION_MAPPER_CONFIG"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="DEFAULT_REQUIRED_ACTIONS" constraintName="FK_DEFAULT_REQUIRED_ACTIONS_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||||
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_AUTH_STATUS" constraintName="AUTH_STATUS_CONSTRAINT" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
|
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_AUTH_STATUS" constraintName="AUTH_STATUS_CONSTRAINT" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
|
||||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATOR" constraintName="FK_AUTHENTICATOR_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATOR" constraintName="FK_AUTHENTICATOR_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATION_FLOW" constraintName="FK_AUTHENTICATION_FLOW_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATION_FLOW" constraintName="FK_AUTHENTICATION_FLOW_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||||
|
|
|
@ -22,9 +22,9 @@ public interface ClientSessionModel {
|
||||||
|
|
||||||
public void setTimestamp(int timestamp);
|
public void setTimestamp(int timestamp);
|
||||||
|
|
||||||
public Action getAction();
|
public String getAction();
|
||||||
|
|
||||||
public void setAction(Action action);
|
public void setAction(String action);
|
||||||
|
|
||||||
public Set<String> getRoles();
|
public Set<String> getRoles();
|
||||||
public void setRoles(Set<String> roles);
|
public void setRoles(Set<String> roles);
|
||||||
|
|
|
@ -156,6 +156,13 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
|
|
||||||
void updateDefaultRoles(String[] defaultRoles);
|
void updateDefaultRoles(String[] defaultRoles);
|
||||||
|
|
||||||
|
Set<String> getDefaultRequiredActions();
|
||||||
|
|
||||||
|
void addDefaultRequiredAction(String action);
|
||||||
|
void removeDefaultRequiredAction(String action);
|
||||||
|
|
||||||
|
void setDefaultRequiredActions(Set<String> action);
|
||||||
|
|
||||||
// Key is clientId
|
// Key is clientId
|
||||||
Map<String, ClientModel> getClientNameMap();
|
Map<String, ClientModel> getClientNameMap();
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ package org.keycloak.models.entities;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -76,6 +78,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
|
||||||
private List<IdentityProviderMapperEntity> identityProviderMappers = new ArrayList<IdentityProviderMapperEntity>();
|
private List<IdentityProviderMapperEntity> identityProviderMappers = new ArrayList<IdentityProviderMapperEntity>();
|
||||||
private List<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
|
private List<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
|
||||||
private List<AuthenticatorEntity> authenticators = new ArrayList<>();
|
private List<AuthenticatorEntity> authenticators = new ArrayList<>();
|
||||||
|
private List<String> defaultRequiredActions = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -500,6 +503,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
|
||||||
public void setAuthenticators(List<AuthenticatorEntity> authenticators) {
|
public void setAuthenticators(List<AuthenticatorEntity> authenticators) {
|
||||||
this.authenticators = authenticators;
|
this.authenticators = authenticators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getDefaultRequiredActions() {
|
||||||
|
return defaultRequiredActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultRequiredActions(List<String> defaultRequiredActions) {
|
||||||
|
this.defaultRequiredActions = defaultRequiredActions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -104,5 +104,7 @@ public class DefaultAuthenticationFlows {
|
||||||
execution.setAutheticatorFlow(false);
|
execution.setAutheticatorFlow(false);
|
||||||
realm.addAuthenticatorExecution(execution);
|
realm.addAuthenticatorExecution(execution);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1548,4 +1548,37 @@ public class RealmAdapter implements RealmModel {
|
||||||
mapper.setConfig(config);
|
mapper.setConfig(config);
|
||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
Set<String> result = new HashSet<String>();
|
||||||
|
if (realm.getDefaultRequiredActions() != null) {
|
||||||
|
result.addAll(realm.getDefaultRequiredActions());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDefaultRequiredAction(String action) {
|
||||||
|
Set<String> actions = getDefaultRequiredActions();
|
||||||
|
actions.add(action);
|
||||||
|
setDefaultRequiredActions(actions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeDefaultRequiredAction(String action) {
|
||||||
|
Set<String> actions = getDefaultRequiredActions();
|
||||||
|
actions.remove(action);
|
||||||
|
setDefaultRequiredActions(actions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultRequiredActions(Set<String> action) {
|
||||||
|
List<String> result = new ArrayList<String>();
|
||||||
|
result.addAll(action);
|
||||||
|
realm.setDefaultRequiredActions(result);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1116,4 +1116,30 @@ public class RealmAdapter implements RealmModel {
|
||||||
if (updated != null) return updated.getAuthenticatorById(id);
|
if (updated != null) return updated.getAuthenticatorById(id);
|
||||||
return cached.getAuthenticators().get(id);
|
return cached.getAuthenticators().get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
return cached.getDefaultRequiredActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDefaultRequiredAction(String action) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.addDefaultRequiredAction(action);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeDefaultRequiredAction(String action) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.removeDefaultRequiredAction(action);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultRequiredActions(Set<String> action) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setDefaultRequiredActions(action);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ public class CachedRealm {
|
||||||
private Set<String> supportedLocales = new HashSet<String>();
|
private Set<String> supportedLocales = new HashSet<String>();
|
||||||
private String defaultLocale;
|
private String defaultLocale;
|
||||||
private MultivaluedHashMap<String, IdentityProviderMapperModel> identityProviderMappers = new MultivaluedHashMap<>();
|
private MultivaluedHashMap<String, IdentityProviderMapperModel> identityProviderMappers = new MultivaluedHashMap<>();
|
||||||
|
private Set<String> defaultRequiredActions = new HashSet<>();
|
||||||
|
|
||||||
public CachedRealm() {
|
public CachedRealm() {
|
||||||
}
|
}
|
||||||
|
@ -200,6 +201,7 @@ public class CachedRealm {
|
||||||
for (AuthenticatorModel authenticator : model.getAuthenticators()) {
|
for (AuthenticatorModel authenticator : model.getAuthenticators()) {
|
||||||
authenticators.put(authenticator.getId(), authenticator);
|
authenticators.put(authenticator.getId(), authenticator);
|
||||||
}
|
}
|
||||||
|
this.defaultRequiredActions.addAll(model.getDefaultRequiredActions());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,4 +440,8 @@ public class CachedRealm {
|
||||||
public Map<String, AuthenticationExecutionModel> getExecutionsById() {
|
public Map<String, AuthenticationExecutionModel> getExecutionsById() {
|
||||||
return executionsById;
|
return executionsById;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
return defaultRequiredActions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1707,5 +1707,30 @@ public class RealmAdapter implements RealmModel {
|
||||||
return authenticators;
|
return authenticators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
Set<String> result = new HashSet<String>();
|
||||||
|
result.addAll(realm.getDefaultRequiredActions());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultRequiredActions(Set<String> actions) {
|
||||||
|
realm.setDefaultRequiredActions(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDefaultRequiredAction(String action) {
|
||||||
|
realm.getDefaultRequiredActions().add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeDefaultRequiredAction(String action) {
|
||||||
|
realm.getDefaultRequiredActions().remove(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -113,6 +113,12 @@ public class RealmEntity {
|
||||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||||
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@Column(name="VALUE")
|
||||||
|
@CollectionTable(name = "DEFAULT_REQUIRED_ACTIONS", joinColumns={ @JoinColumn(name="REALM_ID") })
|
||||||
|
protected Set<String> defaultRequiredActions = new HashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
@ElementCollection
|
@ElementCollection
|
||||||
@MapKeyColumn(name="NAME")
|
@MapKeyColumn(name="NAME")
|
||||||
@Column(name="VALUE")
|
@Column(name="VALUE")
|
||||||
|
@ -568,5 +574,13 @@ public class RealmEntity {
|
||||||
public void setAuthenticationFlows(Collection<AuthenticationFlowEntity> authenticationFlows) {
|
public void setAuthenticationFlows(Collection<AuthenticationFlowEntity> authenticationFlows) {
|
||||||
this.authenticationFlows = authenticationFlows;
|
this.authenticationFlows = authenticationFlows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
return defaultRequiredActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultRequiredActions(Set<String> defaultRequiredActions) {
|
||||||
|
this.defaultRequiredActions = defaultRequiredActions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1590,4 +1590,32 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
mapper.setConfig(config);
|
mapper.setConfig(config);
|
||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getDefaultRequiredActions() {
|
||||||
|
Set<String> result = new HashSet<String>();
|
||||||
|
result.addAll(realm.getDefaultRequiredActions());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultRequiredActions(Set<String> actions) {
|
||||||
|
List<String> result = new ArrayList<String>();
|
||||||
|
result.addAll(actions);
|
||||||
|
getMongoEntity().setDefaultRequiredActions(result);
|
||||||
|
updateMongoEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDefaultRequiredAction(String action) {
|
||||||
|
getMongoStore().pushItemToList(getMongoEntity(), "defaultRequiredActions", action, true, invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeDefaultRequiredAction(String action) {
|
||||||
|
getMongoStore().pullItemFromList(getMongoEntity(), "defaultRequiredActions", action, invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,12 +100,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action getAction() {
|
public String getAction() {
|
||||||
return entity.getAction();
|
return entity.getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAction(Action action) {
|
public void setAction(String action) {
|
||||||
entity.setAction(action);
|
entity.setAction(action);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class ClientSessionEntity extends SessionEntity {
|
||||||
|
|
||||||
private int timestamp;
|
private int timestamp;
|
||||||
|
|
||||||
private ClientSessionModel.Action action;
|
private String action;
|
||||||
|
|
||||||
private Set<String> roles;
|
private Set<String> roles;
|
||||||
private Set<String> protocolMappers;
|
private Set<String> protocolMappers;
|
||||||
|
@ -81,11 +81,11 @@ public class ClientSessionEntity extends SessionEntity {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientSessionModel.Action getAction() {
|
public String getAction() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,12 +189,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action getAction() {
|
public String getAction() {
|
||||||
return entity.getAction();
|
return entity.getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAction(Action action) {
|
public void setAction(String action) {
|
||||||
entity.setAction(action);
|
entity.setAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ public class ClientSessionEntity {
|
||||||
@Column(name="AUTH_METHOD")
|
@Column(name="AUTH_METHOD")
|
||||||
protected String authMethod;
|
protected String authMethod;
|
||||||
|
|
||||||
@Column(name="ACTION")
|
@Column(name="CURRENT_ACTION")
|
||||||
protected ClientSessionModel.Action action;
|
protected String action;
|
||||||
|
|
||||||
@Column(name="AUTH_USER_ID")
|
@Column(name="AUTH_USER_ID")
|
||||||
protected String userId;
|
protected String userId;
|
||||||
|
@ -123,11 +123,11 @@ public class ClientSessionEntity {
|
||||||
this.redirectUri = redirectUri;
|
this.redirectUri = redirectUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientSessionModel.Action getAction() {
|
public String getAction() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,12 +93,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientSessionModel.Action getAction() {
|
public String getAction() {
|
||||||
return entity.getAction();
|
return entity.getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
entity.setAction(action);
|
entity.setAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class ClientSessionEntity {
|
||||||
private String authMethod;
|
private String authMethod;
|
||||||
|
|
||||||
private int timestamp;
|
private int timestamp;
|
||||||
private ClientSessionModel.Action action;
|
private String action;
|
||||||
private Set<String> roles;
|
private Set<String> roles;
|
||||||
private Set<String> protocolMappers;
|
private Set<String> protocolMappers;
|
||||||
private Map<String, String> notes = new HashMap<>();
|
private Map<String, String> notes = new HashMap<>();
|
||||||
|
@ -78,11 +78,11 @@ public class ClientSessionEntity {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientSessionModel.Action getAction() {
|
public String getAction() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,12 +108,12 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action getAction() {
|
public String getAction() {
|
||||||
return entity.getAction();
|
return entity.getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAction(Action action) {
|
public void setAction(String action) {
|
||||||
entity.setAction(action);
|
entity.setAction(action);
|
||||||
updateMongoEntity();
|
updateMongoEntity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class MongoClientSessionEntity extends AbstractIdentifiableEntity impleme
|
||||||
private String authMethod;
|
private String authMethod;
|
||||||
|
|
||||||
private int timestamp;
|
private int timestamp;
|
||||||
private ClientSessionModel.Action action;
|
private String action;
|
||||||
private List<String> roles;
|
private List<String> roles;
|
||||||
private List<String> protocolMappers;
|
private List<String> protocolMappers;
|
||||||
private Map<String, String> notes = new HashMap<String, String>();
|
private Map<String, String> notes = new HashMap<String, String>();
|
||||||
|
@ -82,11 +82,11 @@ public class MongoClientSessionEntity extends AbstractIdentifiableEntity impleme
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientSessionModel.Action getAction() {
|
public String getAction() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.login.LoginFormsProvider;
|
||||||
import org.keycloak.models.AuthenticationFlowModel;
|
import org.keycloak.models.AuthenticationFlowModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientSessionModel;
|
import org.keycloak.models.ClientSessionModel;
|
||||||
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
@ -32,6 +33,7 @@ import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
import org.keycloak.services.ErrorPage;
|
import org.keycloak.services.ErrorPage;
|
||||||
|
import org.keycloak.services.Urls;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.ClientSessionCode;
|
import org.keycloak.services.managers.ClientSessionCode;
|
||||||
import org.keycloak.services.managers.HttpAuthenticationManager;
|
import org.keycloak.services.managers.HttpAuthenticationManager;
|
||||||
|
@ -59,6 +61,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource class for the oauth/openid connect token service
|
* Resource class for the oauth/openid connect token service
|
||||||
|
@ -264,7 +267,7 @@ public class SamlService {
|
||||||
ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
|
ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
|
||||||
clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
|
clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
|
||||||
clientSession.setRedirectUri(redirect);
|
clientSession.setRedirectUri(redirect);
|
||||||
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
|
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
|
||||||
clientSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
|
clientSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
|
||||||
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
|
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
|
||||||
|
@ -317,7 +320,22 @@ public class SamlService {
|
||||||
return forms.createLogin();
|
return forms.createLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response buildRedirectToIdentityProvider(String providerId, String accessCode) {
|
||||||
|
logger.debug("Automatically redirect to identity provider: " + providerId);
|
||||||
|
return Response.temporaryRedirect(
|
||||||
|
Urls.identityProviderAuthnRequest(uriInfo.getBaseUri(), providerId, realm.getName(), accessCode))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected Response newBrowserAuthentication(ClientSessionModel clientSession) {
|
protected Response newBrowserAuthentication(ClientSessionModel clientSession) {
|
||||||
|
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
|
||||||
|
for (IdentityProviderModel identityProvider : identityProviders) {
|
||||||
|
if (identityProvider.isAuthenticateByDefault()) {
|
||||||
|
return buildRedirectToIdentityProvider(identityProvider.getAlias(), new ClientSessionCode(realm, clientSession).getCode() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String flowId = null;
|
String flowId = null;
|
||||||
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
|
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
|
||||||
if (flow.getAlias().equals("browser")) {
|
if (flow.getAlias().equals("browser")) {
|
||||||
|
@ -336,7 +354,11 @@ public class SamlService {
|
||||||
.setUriInfo(uriInfo)
|
.setUriInfo(uriInfo)
|
||||||
.setRequest(request);
|
.setRequest(request);
|
||||||
|
|
||||||
|
try {
|
||||||
return processor.authenticate();
|
return processor.authenticate();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return processor.handleBrowserException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -394,7 +416,7 @@ public class SamlService {
|
||||||
// remove client from logout requests
|
// remove client from logout requests
|
||||||
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
|
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
|
||||||
if (clientSession.getClient().getId().equals(client.getId())) {
|
if (clientSession.getClient().getId().equals(client.getId())) {
|
||||||
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
|
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("browser Logout");
|
logger.debug("browser Logout");
|
||||||
|
@ -405,7 +427,7 @@ public class SamlService {
|
||||||
if (clientSession == null) continue;
|
if (clientSession == null) continue;
|
||||||
if (clientSession.getClient().getClientId().equals(client.getClientId())) {
|
if (clientSession.getClient().getClientId().equals(client.getClientId())) {
|
||||||
// remove requesting client from logout
|
// remove requesting client from logout
|
||||||
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
|
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
|
||||||
}
|
}
|
||||||
UserSessionModel userSession = clientSession.getUserSession();
|
UserSessionModel userSession = clientSession.getUserSession();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.ClientConnection;
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
|
import org.keycloak.events.Errors;
|
||||||
import org.keycloak.events.EventBuilder;
|
import org.keycloak.events.EventBuilder;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.models.AuthenticationExecutionModel;
|
import org.keycloak.models.AuthenticationExecutionModel;
|
||||||
|
@ -15,8 +16,10 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.protocol.oidc.TokenManager;
|
import org.keycloak.protocol.oidc.TokenManager;
|
||||||
|
import org.keycloak.services.ErrorPage;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.BruteForceProtector;
|
import org.keycloak.services.managers.BruteForceProtector;
|
||||||
|
import org.keycloak.services.messages.Messages;
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -39,6 +42,7 @@ public class AuthenticationProcessor {
|
||||||
protected EventBuilder event;
|
protected EventBuilder event;
|
||||||
protected HttpRequest request;
|
protected HttpRequest request;
|
||||||
protected String flowId;
|
protected String flowId;
|
||||||
|
protected String action;
|
||||||
protected boolean userSessionCreated;
|
protected boolean userSessionCreated;
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +138,11 @@ public class AuthenticationProcessor {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthenticationProcessor setAction(String action) {
|
||||||
|
this.action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private class Result implements AuthenticatorContext {
|
private class Result implements AuthenticatorContext {
|
||||||
AuthenticatorModel model;
|
AuthenticatorModel model;
|
||||||
AuthenticationExecutionModel execution;
|
AuthenticationExecutionModel execution;
|
||||||
|
@ -168,6 +177,11 @@ public class AuthenticationProcessor {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAction() {
|
||||||
|
return AuthenticationProcessor.this.action;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authenticator getAuthenticator() {
|
public Authenticator getAuthenticator() {
|
||||||
return authenticator;
|
return authenticator;
|
||||||
|
@ -332,6 +346,34 @@ public class AuthenticationProcessor {
|
||||||
return status == UserSessionModel.AuthenticatorStatus.SUCCESS;
|
return status == UserSessionModel.AuthenticatorStatus.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Response handleBrowserException(Exception failure) {
|
||||||
|
if (failure instanceof AuthException) {
|
||||||
|
AuthException e = (AuthException)failure;
|
||||||
|
logger.error("failed authentication: " + e.getError().toString(), e);
|
||||||
|
if (e.getError() == AuthenticationProcessor.Error.INVALID_USER) {
|
||||||
|
event.error(Errors.USER_NOT_FOUND);
|
||||||
|
return ErrorPage.error(session, Messages.INVALID_USER);
|
||||||
|
} else if (e.getError() == AuthenticationProcessor.Error.USER_DISABLED) {
|
||||||
|
event.error(Errors.USER_DISABLED);
|
||||||
|
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
||||||
|
} else if (e.getError() == AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED) {
|
||||||
|
event.error(Errors.USER_TEMPORARILY_DISABLED);
|
||||||
|
return ErrorPage.error(session, Messages.ACCOUNT_TEMPORARILY_DISABLED);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
event.error(Errors.INVALID_USER_CREDENTIALS);
|
||||||
|
return ErrorPage.error(session, Messages.INVALID_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.error("failed authentication", failure);
|
||||||
|
event.error(Errors.INVALID_USER_CREDENTIALS);
|
||||||
|
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Response authenticate() throws AuthException {
|
public Response authenticate() throws AuthException {
|
||||||
logger.debug("AUTHENTICATE");
|
logger.debug("AUTHENTICATE");
|
||||||
event.event(EventType.LOGIN);
|
event.event(EventType.LOGIN);
|
||||||
|
|
|
@ -31,6 +31,8 @@ public interface AuthenticatorContext {
|
||||||
|
|
||||||
void setAuthenticatorModel(AuthenticatorModel model);
|
void setAuthenticatorModel(AuthenticatorModel model);
|
||||||
|
|
||||||
|
String getAction();
|
||||||
|
|
||||||
Authenticator getAuthenticator();
|
Authenticator getAuthenticator();
|
||||||
|
|
||||||
void setAuthenticator(Authenticator authenticator);
|
void setAuthenticator(Authenticator authenticator);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
|
import org.keycloak.ClientConnection;
|
||||||
|
import org.keycloak.events.EventBuilder;
|
||||||
|
import org.keycloak.models.AuthenticationExecutionModel;
|
||||||
|
import org.keycloak.models.AuthenticatorModel;
|
||||||
|
import org.keycloak.models.ClientSessionModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.services.managers.BruteForceProtector;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface RequiredActionContext {
|
||||||
|
EventBuilder getEvent();
|
||||||
|
UserModel getUser();
|
||||||
|
RealmModel getRealm();
|
||||||
|
ClientSessionModel getClientSession();
|
||||||
|
UserSessionModel getUserSession();
|
||||||
|
ClientConnection getConnection();
|
||||||
|
UriInfo getUriInfo();
|
||||||
|
KeycloakSession getSession();
|
||||||
|
HttpRequest getHttpRequest();
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface RequiredActionProvider extends Provider {
|
||||||
|
Response invokeRequiredAction(RequiredActionContext context);
|
||||||
|
Object jaxrsService();
|
||||||
|
}
|
|
@ -19,26 +19,27 @@ import java.net.URI;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class AbstractFormAuthenticator {
|
public class AbstractFormAuthenticator {
|
||||||
protected boolean isActionUrl(AuthenticatorContext context) {
|
|
||||||
URI expected = LoginActionsService.authenticationFormProcessor(context.getUriInfo()).build(context.getRealm().getName());
|
|
||||||
String current = context.getUriInfo().getAbsolutePath().getPath();
|
|
||||||
String expectedPath = expected.getPath();
|
|
||||||
return expectedPath.equals(current);
|
|
||||||
|
|
||||||
|
public static final String LOGIN_FORM_ACTION = "login_form";
|
||||||
|
public static final String ACTION = "action";
|
||||||
|
|
||||||
|
protected boolean isAction(AuthenticatorContext context, String action) {
|
||||||
|
return action.equals(context.getAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LoginFormsProvider loginForm(AuthenticatorContext context) {
|
protected LoginFormsProvider loginForm(AuthenticatorContext context) {
|
||||||
ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession());
|
ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession());
|
||||||
code.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
code.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
URI action = getActionUrl(context, code);
|
URI action = getActionUrl(context, code, LOGIN_FORM_ACTION);
|
||||||
return context.getSession().getProvider(LoginFormsProvider.class)
|
return context.getSession().getProvider(LoginFormsProvider.class)
|
||||||
.setActionUri(action)
|
.setActionUri(action)
|
||||||
.setClientSessionCode(code.getCode());
|
.setClientSessionCode(code.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code) {
|
public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code, String action) {
|
||||||
return LoginActionsService.authenticationFormProcessor(context.getUriInfo())
|
return LoginActionsService.authenticationFormProcessor(context.getUriInfo())
|
||||||
.queryParam(OAuth2Constants.CODE, code.getCode())
|
.queryParam(OAuth2Constants.CODE, code.getCode())
|
||||||
|
.queryParam(ACTION, action)
|
||||||
.build(context.getRealm().getName());
|
.build(context.getRealm().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(AuthenticatorContext context) {
|
public void authenticate(AuthenticatorContext context) {
|
||||||
if (!isActionUrl(context)) {
|
if (!isAction(context, LOGIN_FORM_ACTION)) {
|
||||||
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
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.messages.Messages;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -28,7 +27,7 @@ public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(AuthenticatorContext context) {
|
public void authenticate(AuthenticatorContext context) {
|
||||||
if (!isActionUrl(context)) {
|
if (!isAction(context, LOGIN_FORM_ACTION)) {
|
||||||
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(AuthenticatorContext context) {
|
public void authenticate(AuthenticatorContext context) {
|
||||||
if (!isActionUrl(context)) {
|
if (!isAction(context, LOGIN_FORM_ACTION)) {
|
||||||
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
|
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
|
||||||
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
|
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.services.managers.ClientSessionCode;
|
import org.keycloak.services.managers.ClientSessionCode;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.services.resources.LoginActionsService;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -26,6 +25,7 @@ import java.util.List;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class OTPFormAuthenticator extends AbstractFormAuthenticator implements Authenticator {
|
public class OTPFormAuthenticator extends AbstractFormAuthenticator implements Authenticator {
|
||||||
|
public static final String TOTP_FORM_ACTION = "totp";
|
||||||
protected AuthenticatorModel model;
|
protected AuthenticatorModel model;
|
||||||
|
|
||||||
public OTPFormAuthenticator(AuthenticatorModel model) {
|
public OTPFormAuthenticator(AuthenticatorModel model) {
|
||||||
|
@ -34,7 +34,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(AuthenticatorContext context) {
|
public void authenticate(AuthenticatorContext context) {
|
||||||
if (!isActionUrl(context)) {
|
if (!isAction(context, TOTP_FORM_ACTION)) {
|
||||||
Response challengeResponse = challenge(context, null);
|
Response challengeResponse = challenge(context, null);
|
||||||
context.challenge(challengeResponse);
|
context.challenge(challengeResponse);
|
||||||
return;
|
return;
|
||||||
|
@ -43,7 +43,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateOTP(AuthenticatorContext context) {
|
public void validateOTP(AuthenticatorContext context) {
|
||||||
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
|
MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
|
||||||
List<UserCredentialModel> credentials = new LinkedList<>();
|
List<UserCredentialModel> credentials = new LinkedList<>();
|
||||||
String password = inputData.getFirst(CredentialRepresentation.TOTP);
|
String password = inputData.getFirst(CredentialRepresentation.TOTP);
|
||||||
if (password == null) {
|
if (password == null) {
|
||||||
|
@ -70,7 +70,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
|
||||||
|
|
||||||
protected Response challenge(AuthenticatorContext context, String error) {
|
protected Response challenge(AuthenticatorContext context, String error) {
|
||||||
ClientSessionCode clientSessionCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
|
ClientSessionCode clientSessionCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
|
||||||
URI action = AbstractFormAuthenticator.getActionUrl(context, clientSessionCode);
|
URI action = AbstractFormAuthenticator.getActionUrl(context, clientSessionCode, TOTP_FORM_ACTION);
|
||||||
LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
|
LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
|
||||||
.setActionUri(action)
|
.setActionUri(action)
|
||||||
.setClientSessionCode(clientSessionCode.getCode());
|
.setClientSessionCode(clientSessionCode.getCode());
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.keycloak.authentication.authenticators;
|
||||||
|
|
||||||
|
import org.keycloak.authentication.AuthenticationProcessor;
|
||||||
|
import org.keycloak.authentication.Authenticator;
|
||||||
|
import org.keycloak.authentication.AuthenticatorContext;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No auth, but it sets a required action.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SetRequiredActionAuthenticator implements Authenticator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresUser() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void authenticate(AuthenticatorContext context) {
|
||||||
|
UserModel user = context.getUser();
|
||||||
|
if (user == null) {
|
||||||
|
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.UNKNOWN_USER);
|
||||||
|
}
|
||||||
|
user.addRequiredAction(context.getAuthenticatorModel().getConfig().get("required.action"));
|
||||||
|
context.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRequiredAction() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package org.keycloak.authentication.authenticators;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.authentication.Authenticator;
|
||||||
|
import org.keycloak.authentication.AuthenticatorFactory;
|
||||||
|
import org.keycloak.models.AuthenticatorModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SetRequiredActionAuthenticatorFactory implements AuthenticatorFactory {
|
||||||
|
public static final String PROVIDER_ID = "auth-set-required-action";
|
||||||
|
static SetRequiredActionAuthenticator SINGLETON = new SetRequiredActionAuthenticator();
|
||||||
|
@Override
|
||||||
|
public Authenticator create(AuthenticatorModel model) {
|
||||||
|
return SINGLETON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authenticator create(KeycloakSession session) {
|
||||||
|
throw new IllegalStateException("illegal call");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return "Action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Set Required Action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpText() {
|
||||||
|
return "Doesn't do any authentication. Instead it just sets a configured required action for the user.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -130,7 +130,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
|
||||||
ClientSessionModel clientSession = accessCode.getClientSession();
|
ClientSessionModel clientSession = accessCode.getClientSession();
|
||||||
String redirect = clientSession.getRedirectUri();
|
String redirect = clientSession.getRedirectUri();
|
||||||
String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
|
String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
|
||||||
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
|
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
|
||||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, accessCode.getCode());
|
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, accessCode.getCode());
|
||||||
log.debugv("redirectAccessCode: state: {0}", state);
|
log.debugv("redirectAccessCode: state: {0}", state);
|
||||||
if (state != null)
|
if (state != null)
|
||||||
|
|
|
@ -220,7 +220,7 @@ public class AuthorizationEndpoint {
|
||||||
clientSession = session.sessions().createClientSession(realm, client);
|
clientSession = session.sessions().createClientSession(realm, client);
|
||||||
clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||||
clientSession.setRedirectUri(redirectUri);
|
clientSession.setRedirectUri(redirectUri);
|
||||||
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
|
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
|
||||||
clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, responseType);
|
clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, responseType);
|
||||||
clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUriParam);
|
clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUriParam);
|
||||||
|
@ -277,7 +277,12 @@ public class AuthorizationEndpoint {
|
||||||
.setUriInfo(uriInfo)
|
.setUriInfo(uriInfo)
|
||||||
.setRequest(request);
|
.setRequest(request);
|
||||||
|
|
||||||
Response challenge = processor.authenticateOnly();
|
Response challenge = null;
|
||||||
|
try {
|
||||||
|
challenge = processor.authenticateOnly();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return processor.handleBrowserException(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (challenge != null && prompt != null && prompt.equals("none")) {
|
if (challenge != null && prompt != null && prompt.equals("none")) {
|
||||||
if (processor.isUserSessionCreated()) {
|
if (processor.isUserSessionCreated()) {
|
||||||
|
|
|
@ -191,7 +191,7 @@ public class TokenEndpoint {
|
||||||
|
|
||||||
ClientSessionModel clientSession = accessCode.getClientSession();
|
ClientSessionModel clientSession = accessCode.getClientSession();
|
||||||
event.detail(Details.CODE_ID, clientSession.getId());
|
event.detail(Details.CODE_ID, clientSession.getId());
|
||||||
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN)) {
|
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
|
||||||
event.error(Errors.INVALID_CODE);
|
event.error(Errors.INVALID_CODE);
|
||||||
throw new ErrorResponseException("invalid_grant", "Code is expired", Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException("invalid_grant", "Code is expired", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ public class AuthenticationManager {
|
||||||
|
|
||||||
public static void backchannelLogoutClientSession(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession, UserSessionModel userSession, UriInfo uriInfo, HttpHeaders headers) {
|
public static void backchannelLogoutClientSession(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession, UserSessionModel userSession, UriInfo uriInfo, HttpHeaders headers) {
|
||||||
ClientModel client = clientSession.getClient();
|
ClientModel client = clientSession.getClient();
|
||||||
if (client instanceof ClientModel && !client.isFrontchannelLogout() && clientSession.getAction() != ClientSessionModel.Action.LOGGED_OUT) {
|
if (client instanceof ClientModel && !client.isFrontchannelLogout() && !ClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) {
|
||||||
String authMethod = clientSession.getAuthMethod();
|
String authMethod = clientSession.getAuthMethod();
|
||||||
if (authMethod == null) return; // must be a keycloak service like account
|
if (authMethod == null) return; // must be a keycloak service like account
|
||||||
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
|
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
|
||||||
|
@ -156,7 +156,7 @@ public class AuthenticationManager {
|
||||||
.setHttpHeaders(headers)
|
.setHttpHeaders(headers)
|
||||||
.setUriInfo(uriInfo);
|
.setUriInfo(uriInfo);
|
||||||
protocol.backchannelLogout(userSession, clientSession);
|
protocol.backchannelLogout(userSession, clientSession);
|
||||||
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
|
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ public class AuthenticationManager {
|
||||||
List<ClientSessionModel> redirectClients = new LinkedList<ClientSessionModel>();
|
List<ClientSessionModel> redirectClients = new LinkedList<ClientSessionModel>();
|
||||||
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
|
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
|
||||||
ClientModel client = clientSession.getClient();
|
ClientModel client = clientSession.getClient();
|
||||||
if (clientSession.getAction() == ClientSessionModel.Action.LOGGED_OUT) continue;
|
if (ClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) continue;
|
||||||
if (client.isFrontchannelLogout()) {
|
if (client.isFrontchannelLogout()) {
|
||||||
String authMethod = clientSession.getAuthMethod();
|
String authMethod = clientSession.getAuthMethod();
|
||||||
if (authMethod == null) continue; // must be a keycloak service like account
|
if (authMethod == null) continue; // must be a keycloak service like account
|
||||||
|
@ -205,7 +205,7 @@ public class AuthenticationManager {
|
||||||
try {
|
try {
|
||||||
logger.debugv("backchannel logout to: {0}", client.getClientId());
|
logger.debugv("backchannel logout to: {0}", client.getClientId());
|
||||||
protocol.backchannelLogout(userSession, clientSession);
|
protocol.backchannelLogout(userSession, clientSession);
|
||||||
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
|
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("Failed to logout client, continuing", e);
|
logger.warn("Failed to logout client, continuing", e);
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ public class AuthenticationManager {
|
||||||
.setHttpHeaders(headers)
|
.setHttpHeaders(headers)
|
||||||
.setUriInfo(uriInfo);
|
.setUriInfo(uriInfo);
|
||||||
// setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not
|
// setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not
|
||||||
nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT);
|
nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
|
||||||
try {
|
try {
|
||||||
logger.debugv("frontchannel logout to: {0}", nextRedirectClient.getClient().getClientId());
|
logger.debugv("frontchannel logout to: {0}", nextRedirectClient.getClient().getClientId());
|
||||||
Response response = protocol.frontchannelLogout(userSession, nextRedirectClient);
|
Response response = protocol.frontchannelLogout(userSession, nextRedirectClient);
|
||||||
|
@ -476,7 +476,7 @@ public class AuthenticationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client.isConsentRequired()) {
|
if (client.isConsentRequired()) {
|
||||||
accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
|
accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT.name());
|
||||||
|
|
||||||
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
|
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,8 @@ public class ClientSessionCode {
|
||||||
return clientSession;
|
return clientSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid(ClientSessionModel.Action requestedAction) {
|
public boolean isValid(String requestedAction) {
|
||||||
ClientSessionModel.Action action = clientSession.getAction();
|
String action = clientSession.getAction();
|
||||||
if (action == null) {
|
if (action == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,18 +93,14 @@ public class ClientSessionCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
int lifespan;
|
int lifespan;
|
||||||
switch (action) {
|
if (action.equals(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
|
||||||
case CODE_TO_TOKEN:
|
|
||||||
lifespan = realm.getAccessCodeLifespan();
|
lifespan = realm.getAccessCodeLifespan();
|
||||||
break;
|
|
||||||
case AUTHENTICATE:
|
|
||||||
lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lifespan = realm.getAccessCodeLifespanUserAction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else if (action.equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
|
||||||
|
lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
|
||||||
|
} else {
|
||||||
|
lifespan = realm.getAccessCodeLifespanUserAction();
|
||||||
|
}
|
||||||
return timestamp + lifespan > Time.currentTime();
|
return timestamp + lifespan > Time.currentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +128,7 @@ public class ClientSessionCode {
|
||||||
return requestedProtocolMappers;
|
return requestedProtocolMappers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(ClientSessionModel.Action action) {
|
public void setAction(String action) {
|
||||||
clientSession.setAction(action);
|
clientSession.setAction(action);
|
||||||
clientSession.setNote(ACTION_KEY, UUID.randomUUID().toString());
|
clientSession.setNote(ACTION_KEY, UUID.randomUUID().toString());
|
||||||
clientSession.setTimestamp(Time.currentTime());
|
clientSession.setTimestamp(Time.currentTime());
|
||||||
|
@ -142,16 +138,16 @@ public class ClientSessionCode {
|
||||||
setAction(convertToAction(requiredAction));
|
setAction(convertToAction(requiredAction));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientSessionModel.Action convertToAction(RequiredAction requiredAction) {
|
private String convertToAction(RequiredAction requiredAction) {
|
||||||
switch (requiredAction) {
|
switch (requiredAction) {
|
||||||
case CONFIGURE_TOTP:
|
case CONFIGURE_TOTP:
|
||||||
return ClientSessionModel.Action.CONFIGURE_TOTP;
|
return ClientSessionModel.Action.CONFIGURE_TOTP.name();
|
||||||
case UPDATE_PASSWORD:
|
case UPDATE_PASSWORD:
|
||||||
return ClientSessionModel.Action.UPDATE_PASSWORD;
|
return ClientSessionModel.Action.UPDATE_PASSWORD.name();
|
||||||
case UPDATE_PROFILE:
|
case UPDATE_PROFILE:
|
||||||
return ClientSessionModel.Action.UPDATE_PROFILE;
|
return ClientSessionModel.Action.UPDATE_PROFILE.name();
|
||||||
case VERIFY_EMAIL:
|
case VERIFY_EMAIL:
|
||||||
return ClientSessionModel.Action.VERIFY_EMAIL;
|
return ClientSessionModel.Action.VERIFY_EMAIL.name();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown required action " + requiredAction);
|
throw new IllegalArgumentException("Unknown required action " + requiredAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -738,7 +738,7 @@ public class AccountService {
|
||||||
try {
|
try {
|
||||||
ClientSessionModel clientSession = auth.getClientSession();
|
ClientSessionModel clientSession = auth.getClientSession();
|
||||||
ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
|
ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
|
||||||
clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
clientSession.setRedirectUri(redirectUri);
|
clientSession.setRedirectUri(redirectUri);
|
||||||
clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, UUID.randomUUID().toString());
|
clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
|
|
@ -373,7 +373,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
private ClientSessionCode parseClientSessionCode(String code) {
|
private ClientSessionCode parseClientSessionCode(String code) {
|
||||||
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
|
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
|
||||||
|
|
||||||
if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
|
if (clientCode != null && clientCode.isValid(AUTHENTICATE.name())) {
|
||||||
ClientSessionModel clientSession = clientCode.getClientSession();
|
ClientSessionModel clientSession = clientCode.getClientSession();
|
||||||
|
|
||||||
if (clientSession != null) {
|
if (clientSession != null) {
|
||||||
|
|
|
@ -166,7 +166,7 @@ public class LoginActionsService {
|
||||||
ClientSessionCode clientCode;
|
ClientSessionCode clientCode;
|
||||||
Response response;
|
Response response;
|
||||||
|
|
||||||
boolean check(String code, ClientSessionModel.Action requiredAction) {
|
boolean check(String code, String requiredAction) {
|
||||||
if (!check(code)) {
|
if (!check(code)) {
|
||||||
return false;
|
return false;
|
||||||
} else if (!clientCode.isValid(requiredAction)) {
|
} else if (!clientCode.isValid(requiredAction)) {
|
||||||
|
@ -178,7 +178,7 @@ public class LoginActionsService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean check(String code, ClientSessionModel.Action requiredAction, ClientSessionModel.Action alternativeRequiredAction) {
|
boolean check(String code, String requiredAction, String alternativeRequiredAction) {
|
||||||
if (!check(code)) {
|
if (!check(code)) {
|
||||||
return false;
|
return false;
|
||||||
} else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) {
|
} else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) {
|
||||||
|
@ -231,9 +231,9 @@ public class LoginActionsService {
|
||||||
ClientSessionCode clientSessionCode = checks.clientCode;
|
ClientSessionCode clientSessionCode = checks.clientCode;
|
||||||
ClientSessionModel clientSession = clientSessionCode.getClientSession();
|
ClientSessionModel clientSession = clientSessionCode.getClientSession();
|
||||||
|
|
||||||
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
|
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
|
||||||
TokenManager.dettachClientSession(session.sessions(), realm, clientSession);
|
TokenManager.dettachClientSession(session.sessions(), realm, clientSession);
|
||||||
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
return session.getProvider(LoginFormsProvider.class)
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
|
@ -281,7 +281,8 @@ public class LoginActionsService {
|
||||||
@Path("auth-form")
|
@Path("auth-form")
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response authForm(@QueryParam("code") String code) {
|
public Response authForm(@QueryParam("code") String code,
|
||||||
|
@QueryParam("action") String action) {
|
||||||
event.event(EventType.LOGIN);
|
event.event(EventType.LOGIN);
|
||||||
if (!checkSsl()) {
|
if (!checkSsl()) {
|
||||||
event.error(Errors.SSL_REQUIRED);
|
event.error(Errors.SSL_REQUIRED);
|
||||||
|
@ -301,8 +302,8 @@ public class LoginActionsService {
|
||||||
ClientSessionModel clientSession = clientCode.getClientSession();
|
ClientSessionModel clientSession = clientCode.getClientSession();
|
||||||
event.detail(Details.CODE_ID, clientSession.getId());
|
event.detail(Details.CODE_ID, clientSession.getId());
|
||||||
|
|
||||||
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
|
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
|
||||||
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
||||||
return session.getProvider(LoginFormsProvider.class)
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
.setError(Messages.EXPIRED_CODE)
|
.setError(Messages.EXPIRED_CODE)
|
||||||
|
@ -338,39 +339,17 @@ public class LoginActionsService {
|
||||||
.setRealm(realm)
|
.setRealm(realm)
|
||||||
.setSession(session)
|
.setSession(session)
|
||||||
.setUriInfo(uriInfo)
|
.setUriInfo(uriInfo)
|
||||||
|
.setAction(action)
|
||||||
.setRequest(request);
|
.setRequest(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return processor.authenticate();
|
return processor.authenticate();
|
||||||
} catch (AuthenticationProcessor.AuthException e) {
|
|
||||||
return handleError(e, code);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
event.error(Errors.INVALID_USER_CREDENTIALS);
|
return processor.handleBrowserException(e);
|
||||||
logger.error("failed authentication", e);
|
|
||||||
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Response handleError(AuthenticationProcessor.AuthException e, String code) {
|
|
||||||
logger.error("failed authentication: " + e.getError().toString(), e);
|
|
||||||
if (e.getError() == AuthenticationProcessor.Error.INVALID_USER) {
|
|
||||||
event.error(Errors.USER_NOT_FOUND);
|
|
||||||
return ErrorPage.error(session, Messages.INVALID_USER);
|
|
||||||
} else if (e.getError() == AuthenticationProcessor.Error.USER_DISABLED) {
|
|
||||||
event.error(Errors.USER_DISABLED);
|
|
||||||
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
|
|
||||||
} else if (e.getError() == AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED) {
|
|
||||||
event.error(Errors.USER_TEMPORARILY_DISABLED);
|
|
||||||
return ErrorPage.error(session, Messages.ACCOUNT_TEMPORARILY_DISABLED);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
event.error(Errors.INVALID_USER_CREDENTIALS);
|
|
||||||
return ErrorPage.error(session, Messages.INVALID_USER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL called after login page. YOU SHOULD NEVER INVOKE THIS DIRECTLY!
|
* URL called after login page. YOU SHOULD NEVER INVOKE THIS DIRECTLY!
|
||||||
*
|
*
|
||||||
|
@ -402,8 +381,8 @@ public class LoginActionsService {
|
||||||
ClientSessionModel clientSession = clientCode.getClientSession();
|
ClientSessionModel clientSession = clientCode.getClientSession();
|
||||||
event.detail(Details.CODE_ID, clientSession.getId());
|
event.detail(Details.CODE_ID, clientSession.getId());
|
||||||
|
|
||||||
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
|
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
|
||||||
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||||
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
||||||
return session.getProvider(LoginFormsProvider.class)
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
.setError(Messages.EXPIRED_CODE)
|
.setError(Messages.EXPIRED_CODE)
|
||||||
|
@ -538,7 +517,7 @@ public class LoginActionsService {
|
||||||
event.error(Errors.INVALID_CODE);
|
event.error(Errors.INVALID_CODE);
|
||||||
return ErrorPage.error(session, Messages.INVALID_CODE);
|
return ErrorPage.error(session, Messages.INVALID_CODE);
|
||||||
}
|
}
|
||||||
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE)) {
|
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name())) {
|
||||||
event.error(Errors.INVALID_CODE);
|
event.error(Errors.INVALID_CODE);
|
||||||
return ErrorPage.error(session, Messages.INVALID_CODE);
|
return ErrorPage.error(session, Messages.INVALID_CODE);
|
||||||
}
|
}
|
||||||
|
@ -676,7 +655,7 @@ public class LoginActionsService {
|
||||||
String code = formData.getFirst("code");
|
String code = formData.getFirst("code");
|
||||||
|
|
||||||
ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
|
ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
|
||||||
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT)) {
|
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT.name())) {
|
||||||
event.error(Errors.INVALID_CODE);
|
event.error(Errors.INVALID_CODE);
|
||||||
return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE);
|
return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE);
|
||||||
}
|
}
|
||||||
|
@ -742,7 +721,7 @@ public class LoginActionsService {
|
||||||
final MultivaluedMap<String, String> formData) {
|
final MultivaluedMap<String, String> formData) {
|
||||||
event.event(EventType.UPDATE_PROFILE);
|
event.event(EventType.UPDATE_PROFILE);
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PROFILE)) {
|
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PROFILE.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -804,7 +783,7 @@ public class LoginActionsService {
|
||||||
final MultivaluedMap<String, String> formData) {
|
final MultivaluedMap<String, String> formData) {
|
||||||
event.event(EventType.UPDATE_TOTP);
|
event.event(EventType.UPDATE_TOTP);
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(code, ClientSessionModel.Action.CONFIGURE_TOTP)) {
|
if (!checks.check(code, ClientSessionModel.Action.CONFIGURE_TOTP.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -849,7 +828,7 @@ public class LoginActionsService {
|
||||||
final MultivaluedMap<String, String> formData) {
|
final MultivaluedMap<String, String> formData) {
|
||||||
event.event(EventType.UPDATE_PASSWORD);
|
event.event(EventType.UPDATE_PASSWORD);
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PASSWORD, ClientSessionModel.Action.RECOVER_PASSWORD)) {
|
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PASSWORD.name(), ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -890,7 +869,7 @@ public class LoginActionsService {
|
||||||
|
|
||||||
event.event(EventType.UPDATE_PASSWORD).success();
|
event.event(EventType.UPDATE_PASSWORD).success();
|
||||||
|
|
||||||
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
|
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
|
||||||
String actionCookieValue = getActionCookie();
|
String actionCookieValue = getActionCookie();
|
||||||
if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) {
|
if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) {
|
||||||
return session.getProvider(LoginFormsProvider.class)
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
|
@ -911,7 +890,7 @@ public class LoginActionsService {
|
||||||
event.event(EventType.VERIFY_EMAIL);
|
event.event(EventType.VERIFY_EMAIL);
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(key, ClientSessionModel.Action.VERIFY_EMAIL)) {
|
if (!checks.check(key, ClientSessionModel.Action.VERIFY_EMAIL.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -937,7 +916,7 @@ public class LoginActionsService {
|
||||||
return redirectOauth(user, accessCode, clientSession, userSession);
|
return redirectOauth(user, accessCode, clientSession, userSession);
|
||||||
} else {
|
} else {
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(code, ClientSessionModel.Action.VERIFY_EMAIL)) {
|
if (!checks.check(code, ClientSessionModel.Action.VERIFY_EMAIL.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -960,7 +939,7 @@ public class LoginActionsService {
|
||||||
event.event(EventType.RESET_PASSWORD);
|
event.event(EventType.RESET_PASSWORD);
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
Checks checks = new Checks();
|
Checks checks = new Checks();
|
||||||
if (!checks.check(key, ClientSessionModel.Action.RECOVER_PASSWORD)) {
|
if (!checks.check(key, ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
|
||||||
return checks.response;
|
return checks.response;
|
||||||
}
|
}
|
||||||
ClientSessionCode accessCode = checks.clientCode;
|
ClientSessionCode accessCode = checks.clientCode;
|
||||||
|
@ -1038,7 +1017,7 @@ public class LoginActionsService {
|
||||||
event.session(userSession);
|
event.session(userSession);
|
||||||
TokenManager.attachClientSession(userSession, clientSession);
|
TokenManager.attachClientSession(userSession, clientSession);
|
||||||
|
|
||||||
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
|
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD.name());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
|
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
|
||||||
|
|
|
@ -788,7 +788,7 @@ public class UsersResource {
|
||||||
|
|
||||||
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
|
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
|
||||||
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
|
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
|
||||||
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
|
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD.name());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
|
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
|
||||||
|
@ -838,7 +838,7 @@ public class UsersResource {
|
||||||
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
|
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
|
||||||
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
|
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
|
||||||
|
|
||||||
accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL);
|
accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL.name());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
|
UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
|
||||||
|
|
|
@ -4,3 +4,4 @@ org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory
|
||||||
org.keycloak.authentication.authenticators.LoginFormUsernameAuthenticatorFactory
|
org.keycloak.authentication.authenticators.LoginFormUsernameAuthenticatorFactory
|
||||||
org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory
|
org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory
|
||||||
org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory
|
org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory
|
||||||
|
org.keycloak.authentication.authenticators.SetRequiredActionAuthenticatorFactory
|
|
@ -166,7 +166,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
|
||||||
private ClientSessionCode parseClientSessionCode(String code) {
|
private ClientSessionCode parseClientSessionCode(String code) {
|
||||||
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realm);
|
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realm);
|
||||||
|
|
||||||
if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
|
if (clientCode != null && clientCode.isValid(AUTHENTICATE.name())) {
|
||||||
ClientSessionModel clientSession = clientCode.getClientSession();
|
ClientSessionModel clientSession = clientCode.getClientSession();
|
||||||
|
|
||||||
if (clientSession != null) {
|
if (clientSession != null) {
|
||||||
|
|
|
@ -117,14 +117,14 @@ public class UserSessionProviderTest {
|
||||||
int time = clientSession.getTimestamp();
|
int time = clientSession.getTimestamp();
|
||||||
assertEquals(null, clientSession.getAction());
|
assertEquals(null, clientSession.getAction());
|
||||||
|
|
||||||
clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
|
clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
|
||||||
clientSession.setTimestamp(time + 10);
|
clientSession.setTimestamp(time + 10);
|
||||||
|
|
||||||
kc.stopSession(session, true);
|
kc.stopSession(session, true);
|
||||||
session = kc.startSession();
|
session = kc.startSession();
|
||||||
|
|
||||||
ClientSessionModel updated = session.sessions().getClientSession(realm, id);
|
ClientSessionModel updated = session.sessions().getClientSession(realm, id);
|
||||||
assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN, updated.getAction());
|
assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN.name(), updated.getAction());
|
||||||
assertEquals(time + 10, updated.getTimestamp());
|
assertEquals(time + 10, updated.getTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue