KEYCLOAK-2152 KEYCLOAK-2061 Client switches changes. Support for response_types and grant_types in OIDC Client registration
This commit is contained in:
parent
0492d84b59
commit
ec327c99f4
28 changed files with 241 additions and 61 deletions
|
@ -23,4 +23,19 @@ public class CollectionUtil {
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if all items from col1 are in col2 and viceversa. Order is not taken into account
|
||||||
|
public static <T> boolean collectionEquals(Collection<T> col1, Collection<T> col2) {
|
||||||
|
if (col1.size() != col2.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (T item : col1) {
|
||||||
|
if (!col2.contains(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
<column name="IMPLICIT_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
|
<column name="IMPLICIT_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
<column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
|
<column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
</addColumn>
|
</addColumn>
|
||||||
|
|
|
@ -27,6 +27,8 @@ public interface OAuth2Constants {
|
||||||
|
|
||||||
String AUTHORIZATION_CODE = "authorization_code";
|
String AUTHORIZATION_CODE = "authorization_code";
|
||||||
|
|
||||||
|
String IMPLICIT = "implicit";
|
||||||
|
|
||||||
String PASSWORD = "password";
|
String PASSWORD = "password";
|
||||||
|
|
||||||
String CLIENT_CREDENTIALS = "client_credentials";
|
String CLIENT_CREDENTIALS = "client_credentials";
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class ClientRepresentation {
|
||||||
protected Boolean implicitFlowEnabled;
|
protected Boolean implicitFlowEnabled;
|
||||||
protected Boolean directAccessGrantsEnabled;
|
protected Boolean directAccessGrantsEnabled;
|
||||||
protected Boolean serviceAccountsEnabled;
|
protected Boolean serviceAccountsEnabled;
|
||||||
|
@Deprecated
|
||||||
protected Boolean directGrantsOnly;
|
protected Boolean directGrantsOnly;
|
||||||
protected Boolean publicClient;
|
protected Boolean publicClient;
|
||||||
protected Boolean frontchannelLogout;
|
protected Boolean frontchannelLogout;
|
||||||
|
@ -216,6 +217,7 @@ public class ClientRepresentation {
|
||||||
this.serviceAccountsEnabled = serviceAccountsEnabled;
|
this.serviceAccountsEnabled = serviceAccountsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Boolean isDirectGrantsOnly() {
|
public Boolean isDirectGrantsOnly() {
|
||||||
return directGrantsOnly;
|
return directGrantsOnly;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ public class OIDCClientRepresentation {
|
||||||
|
|
||||||
private String token_endpoint_auth_method;
|
private String token_endpoint_auth_method;
|
||||||
|
|
||||||
private String grant_types;
|
private List<String> grant_types;
|
||||||
|
|
||||||
private String response_types;
|
private List<String> response_types;
|
||||||
|
|
||||||
private String client_id;
|
private String client_id;
|
||||||
|
|
||||||
|
@ -68,19 +68,19 @@ public class OIDCClientRepresentation {
|
||||||
this.token_endpoint_auth_method = token_endpoint_auth_method;
|
this.token_endpoint_auth_method = token_endpoint_auth_method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGrantTypes() {
|
public List<String> getGrantTypes() {
|
||||||
return grant_types;
|
return grant_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGrantTypes(String grantTypes) {
|
public void setGrantTypes(List<String> grantTypes) {
|
||||||
this.grant_types = grantTypes;
|
this.grant_types = grantTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResponseTypes() {
|
public List<String> getResponseTypes() {
|
||||||
return response_types;
|
return response_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResponseTypes(String responseTypes) {
|
public void setResponseTypes(List<String> responseTypes) {
|
||||||
this.response_types = responseTypes;
|
this.response_types = responseTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ public interface Details {
|
||||||
String REDIRECT_URI = "redirect_uri";
|
String REDIRECT_URI = "redirect_uri";
|
||||||
String RESPONSE_TYPE = "response_type";
|
String RESPONSE_TYPE = "response_type";
|
||||||
String RESPONSE_MODE = "response_mode";
|
String RESPONSE_MODE = "response_mode";
|
||||||
|
String GRANT_TYPE = "grant_type";
|
||||||
String AUTH_TYPE = "auth_type";
|
String AUTH_TYPE = "auth_type";
|
||||||
String AUTH_METHOD = "auth_method";
|
String AUTH_METHOD = "auth_method";
|
||||||
String IDENTITY_PROVIDER = "identity_provider";
|
String IDENTITY_PROVIDER = "identity_provider";
|
||||||
|
|
|
@ -865,7 +865,6 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
|
||||||
$scope.client = {
|
$scope.client = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
standardFlowEnabled: true,
|
standardFlowEnabled: true,
|
||||||
directAccessGrantsEnabled: true,
|
|
||||||
attributes: {}
|
attributes: {}
|
||||||
};
|
};
|
||||||
$scope.client.attributes['saml_signature_canonicalization_method'] = $scope.canonicalization[0].value;
|
$scope.client.attributes['saml_signature_canonicalization_method'] = $scope.canonicalization[0].value;
|
||||||
|
|
|
@ -34,7 +34,6 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
||||||
private boolean implicitFlowEnabled;
|
private boolean implicitFlowEnabled;
|
||||||
private boolean directAccessGrantsEnabled;
|
private boolean directAccessGrantsEnabled;
|
||||||
private boolean serviceAccountsEnabled;
|
private boolean serviceAccountsEnabled;
|
||||||
private boolean directGrantsOnly;
|
|
||||||
private int nodeReRegistrationTimeout;
|
private int nodeReRegistrationTimeout;
|
||||||
|
|
||||||
// We are using names of defaultRoles (not ids)
|
// We are using names of defaultRoles (not ids)
|
||||||
|
@ -278,14 +277,6 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
||||||
this.serviceAccountsEnabled = serviceAccountsEnabled;
|
this.serviceAccountsEnabled = serviceAccountsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDirectGrantsOnly() {
|
|
||||||
return directGrantsOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDirectGrantsOnly(boolean directGrantsOnly) {
|
|
||||||
this.directGrantsOnly = directGrantsOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getDefaultRoles() {
|
public List<String> getDefaultRoles() {
|
||||||
return defaultRoles;
|
return defaultRoles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,17 +776,19 @@ public class RepresentationToModel {
|
||||||
if (resourceRep.getBaseUrl() != null) client.setBaseUrl(resourceRep.getBaseUrl());
|
if (resourceRep.getBaseUrl() != null) client.setBaseUrl(resourceRep.getBaseUrl());
|
||||||
if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly());
|
if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly());
|
||||||
if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired());
|
if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired());
|
||||||
if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
|
|
||||||
if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
|
|
||||||
if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
|
|
||||||
if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
|
|
||||||
|
|
||||||
// Backwards compatibility only
|
// Backwards compatibility only
|
||||||
if (resourceRep.isDirectGrantsOnly() != null) {
|
if (resourceRep.isDirectGrantsOnly() != null) {
|
||||||
logger.warn("Using deprecated 'directGrantsOnly' configuration in JSON representation. It will be removed in future versions");
|
logger.warn("Using deprecated 'directGrantsOnly' configuration in JSON representation. It will be removed in future versions");
|
||||||
client.setStandardFlowEnabled(!resourceRep.isDirectGrantsOnly());
|
client.setStandardFlowEnabled(!resourceRep.isDirectGrantsOnly());
|
||||||
|
client.setDirectAccessGrantsEnabled(resourceRep.isDirectGrantsOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
|
||||||
|
if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
|
||||||
|
if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
|
||||||
|
if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
|
||||||
|
|
||||||
if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
|
if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
|
||||||
if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
|
if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
|
||||||
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
||||||
|
|
|
@ -726,7 +726,6 @@ public class RealmAdapter implements RealmModel {
|
||||||
entity.setClientId(clientId);
|
entity.setClientId(clientId);
|
||||||
entity.setEnabled(true);
|
entity.setEnabled(true);
|
||||||
entity.setStandardFlowEnabled(true);
|
entity.setStandardFlowEnabled(true);
|
||||||
entity.setDirectAccessGrantsEnabled(true);
|
|
||||||
entity.setRealm(realm);
|
entity.setRealm(realm);
|
||||||
realm.getClients().add(entity);
|
realm.getClients().add(entity);
|
||||||
em.persist(entity);
|
em.persist(entity);
|
||||||
|
|
|
@ -811,7 +811,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
clientEntity.setRealmId(getId());
|
clientEntity.setRealmId(getId());
|
||||||
clientEntity.setEnabled(true);
|
clientEntity.setEnabled(true);
|
||||||
clientEntity.setStandardFlowEnabled(true);
|
clientEntity.setStandardFlowEnabled(true);
|
||||||
clientEntity.setDirectAccessGrantsEnabled(true);
|
|
||||||
getMongoStore().insertEntity(clientEntity, invocationContext);
|
getMongoStore().insertEntity(clientEntity, invocationContext);
|
||||||
|
|
||||||
final ClientModel model = new ClientAdapter(session, this, clientEntity, invocationContext);
|
final ClientModel model = new ClientAdapter(session, this, clientEntity, invocationContext);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.saml.EntityDescriptorDescriptionConverter;
|
import org.keycloak.protocol.saml.EntityDescriptorDescriptionConverter;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
|
import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
|
||||||
|
import org.keycloak.services.clientregistration.ClientRegistrationException;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
|
import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
|
||||||
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationService;
|
import org.keycloak.services.clientregistration.ClientRegistrationService;
|
||||||
import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory;
|
import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
@ -22,13 +23,13 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
|
||||||
|
|
||||||
public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
|
public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
|
||||||
|
|
||||||
public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
|
public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
|
||||||
|
|
||||||
public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE);
|
public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
|
||||||
|
|
||||||
public static final List<String> DEFAULT_SUBJECT_TYPES_SUPPORTED = list("public");
|
public static final List<String> DEFAULT_SUBJECT_TYPES_SUPPORTED = list("public");
|
||||||
|
|
||||||
public static final List<String> DEFAULT_RESPONSE_MODES_SUPPORTED = list("query");
|
public static final List<String> DEFAULT_RESPONSE_MODES_SUPPORTED = list("query", "fragment", "form_post");
|
||||||
|
|
||||||
private KeycloakSession session;
|
private KeycloakSession session;
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,8 @@ public class TokenEndpoint {
|
||||||
} else {
|
} else {
|
||||||
throw new ErrorResponseException(Errors.INVALID_REQUEST, "Invalid " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException(Errors.INVALID_REQUEST, "Invalid " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.detail(Details.GRANT_TYPE, grantType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response buildAuthorizationCodeAccessTokenResponse() {
|
public Response buildAuthorizationCodeAccessTokenResponse() {
|
||||||
|
@ -327,7 +329,7 @@ public class TokenEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response buildResourceOwnerPasswordCredentialsGrant() {
|
public Response buildResourceOwnerPasswordCredentialsGrant() {
|
||||||
event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD);
|
event.detail(Details.AUTH_METHOD, "oauth_credentials");
|
||||||
|
|
||||||
if (client.isConsentRequired()) {
|
if (client.isConsentRequired()) {
|
||||||
event.error(Errors.CONSENT_DENIED);
|
event.error(Errors.CONSENT_DENIED);
|
||||||
|
@ -393,8 +395,6 @@ public class TokenEndpoint {
|
||||||
throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
|
throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS);
|
|
||||||
|
|
||||||
UserModel clientUser = session.users().getUserByServiceAccountClient(client);
|
UserModel clientUser = session.users().getUserByServiceAccountClient(client);
|
||||||
|
|
||||||
if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
|
if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public abstract class OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
|
|
||||||
// http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
|
// http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
|
||||||
public static class QueryRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
private static class QueryRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
protected QueryRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
|
protected QueryRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
|
||||||
super(uriBuilder);
|
super(uriBuilder);
|
||||||
|
@ -64,7 +64,7 @@ public abstract class OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
|
|
||||||
// http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
|
// http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
|
||||||
public static class FragmentRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
private static class FragmentRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
private StringBuilder fragment;
|
private StringBuilder fragment;
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ public abstract class OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
|
|
||||||
// http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
// http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
||||||
public static class FormPostRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
private static class FormPostRedirectUriBuilder extends OIDCRedirectUriBuilder {
|
||||||
|
|
||||||
private Map<String, String> params = new HashMap<>();
|
private Map<String, String> params = new HashMap<>();
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,16 @@ public class OIDCResponseType {
|
||||||
return new OIDCResponseType(allowedTypes);
|
return new OIDCResponseType(allowedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OIDCResponseType parse(List<String> responseTypes) {
|
||||||
|
OIDCResponseType result = new OIDCResponseType(new ArrayList<String>());
|
||||||
|
for (String respType : responseTypes) {
|
||||||
|
OIDCResponseType responseType = parse(respType);
|
||||||
|
result.responseTypes.addAll(responseType.responseTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateAllowedTypes(List<String> responseTypes) {
|
private static void validateAllowedTypes(List<String> responseTypes) {
|
||||||
if (responseTypes.size() == 0) {
|
if (responseTypes.size() == 0) {
|
||||||
throw new IllegalStateException("No responseType provided");
|
throw new IllegalStateException("No responseType provided");
|
||||||
|
@ -53,9 +63,6 @@ public class OIDCResponseType {
|
||||||
if (responseTypes.contains(NONE) && responseTypes.size() > 1) {
|
if (responseTypes.contains(NONE) && responseTypes.size() > 1) {
|
||||||
throw new IllegalArgumentException("None not allowed with some other response_type");
|
throw new IllegalArgumentException("None not allowed with some other response_type");
|
||||||
}
|
}
|
||||||
if (responseTypes.contains(ID_TOKEN) && responseTypes.size() == 1) {
|
|
||||||
throw new IllegalArgumentException("Not supported to use response_type=id_token alone");
|
|
||||||
}
|
|
||||||
if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) {
|
if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) {
|
||||||
throw new IllegalArgumentException("Not supported to use response_type=token alone");
|
throw new IllegalArgumentException("Not supported to use response_type=token alone");
|
||||||
}
|
}
|
||||||
|
@ -72,7 +79,7 @@ public class OIDCResponseType {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isImplicitFlow() {
|
public boolean isImplicitFlow() {
|
||||||
return hasResponseType(TOKEN) && hasResponseType(ID_TOKEN) && !hasResponseType(CODE);
|
return hasResponseType(ID_TOKEN) && !hasResponseType(CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.keycloak.services.clientregistration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ClientRegistrationException extends RuntimeException {
|
||||||
|
|
||||||
|
public ClientRegistrationException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationException(Throwable throwable) {
|
||||||
|
super(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationException(String message, Throwable throwable) {
|
||||||
|
super(message, throwable);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,48 @@
|
||||||
package org.keycloak.services.clientregistration.oidc;
|
package org.keycloak.services.clientregistration.oidc;
|
||||||
|
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
||||||
|
import org.keycloak.services.clientregistration.ClientRegistrationException;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class DescriptionConverter {
|
public class DescriptionConverter {
|
||||||
|
|
||||||
public static ClientRepresentation toInternal(OIDCClientRepresentation clientOIDC) {
|
public static ClientRepresentation toInternal(OIDCClientRepresentation clientOIDC) throws ClientRegistrationException {
|
||||||
ClientRepresentation client = new ClientRepresentation();
|
ClientRepresentation client = new ClientRepresentation();
|
||||||
client.setClientId(clientOIDC.getClientId());
|
client.setClientId(clientOIDC.getClientId());
|
||||||
client.setName(clientOIDC.getClientName());
|
client.setName(clientOIDC.getClientName());
|
||||||
client.setRedirectUris(clientOIDC.getRedirectUris());
|
client.setRedirectUris(clientOIDC.getRedirectUris());
|
||||||
client.setBaseUrl(clientOIDC.getClientUri());
|
client.setBaseUrl(clientOIDC.getClientUri());
|
||||||
|
|
||||||
|
List<String> oidcResponseTypes = clientOIDC.getResponseTypes();
|
||||||
|
if (oidcResponseTypes == null || oidcResponseTypes.isEmpty()) {
|
||||||
|
oidcResponseTypes = Collections.singletonList(OIDCResponseType.CODE);
|
||||||
|
}
|
||||||
|
List<String> oidcGrantTypes = clientOIDC.getGrantTypes();
|
||||||
|
|
||||||
|
try {
|
||||||
|
OIDCResponseType responseType = OIDCResponseType.parse(oidcResponseTypes);
|
||||||
|
client.setStandardFlowEnabled(responseType.hasResponseType(OIDCResponseType.CODE));
|
||||||
|
client.setImplicitFlowEnabled(responseType.isImplicitOrHybridFlow());
|
||||||
|
if (oidcGrantTypes != null) {
|
||||||
|
client.setDirectAccessGrantsEnabled(oidcGrantTypes.contains(OAuth2Constants.PASSWORD));
|
||||||
|
client.setServiceAccountsEnabled(oidcGrantTypes.contains(OAuth2Constants.CLIENT_CREDENTIALS));
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
throw new ClientRegistrationException(iae.getMessage(), iae);
|
||||||
|
}
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +55,45 @@ public class DescriptionConverter {
|
||||||
response.setRedirectUris(client.getRedirectUris());
|
response.setRedirectUris(client.getRedirectUris());
|
||||||
response.setRegistrationAccessToken(client.getRegistrationAccessToken());
|
response.setRegistrationAccessToken(client.getRegistrationAccessToken());
|
||||||
response.setRegistrationClientUri(uri.toString());
|
response.setRegistrationClientUri(uri.toString());
|
||||||
|
response.setResponseTypes(getOIDCResponseTypes(client));
|
||||||
|
response.setGrantTypes(getOIDCGrantTypes(client));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<String> getOIDCResponseTypes(ClientRepresentation client) {
|
||||||
|
List<String> responseTypes = new ArrayList<>();
|
||||||
|
if (client.isStandardFlowEnabled()) {
|
||||||
|
responseTypes.add(OAuth2Constants.CODE);
|
||||||
|
responseTypes.add(OIDCResponseType.NONE);
|
||||||
|
}
|
||||||
|
if (client.isImplicitFlowEnabled()) {
|
||||||
|
responseTypes.add(OIDCResponseType.ID_TOKEN);
|
||||||
|
responseTypes.add("id_token token");
|
||||||
|
}
|
||||||
|
if (client.isStandardFlowEnabled() && client.isImplicitFlowEnabled()) {
|
||||||
|
responseTypes.add("code id_token");
|
||||||
|
responseTypes.add("code token");
|
||||||
|
responseTypes.add("code id_token token");
|
||||||
|
}
|
||||||
|
return responseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> getOIDCGrantTypes(ClientRepresentation client) {
|
||||||
|
List<String> grantTypes = new ArrayList<>();
|
||||||
|
if (client.isStandardFlowEnabled()) {
|
||||||
|
grantTypes.add(OAuth2Constants.AUTHORIZATION_CODE);
|
||||||
|
}
|
||||||
|
if (client.isImplicitFlowEnabled()) {
|
||||||
|
grantTypes.add(OAuth2Constants.IMPLICIT);
|
||||||
|
}
|
||||||
|
if (client.isDirectAccessGrantsEnabled()) {
|
||||||
|
grantTypes.add(OAuth2Constants.PASSWORD);
|
||||||
|
}
|
||||||
|
if (client.isServiceAccountsEnabled()) {
|
||||||
|
grantTypes.add(OAuth2Constants.CLIENT_CREDENTIALS);
|
||||||
|
}
|
||||||
|
grantTypes.add(OAuth2Constants.REFRESH_TOKEN);
|
||||||
|
return grantTypes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.services.clientregistration.oidc;
|
package org.keycloak.services.clientregistration.oidc;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.events.EventBuilder;
|
import org.keycloak.events.EventBuilder;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -9,6 +10,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
|
import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationAuth;
|
import org.keycloak.services.clientregistration.ClientRegistrationAuth;
|
||||||
|
import org.keycloak.services.clientregistration.ClientRegistrationException;
|
||||||
import org.keycloak.services.clientregistration.ErrorCodes;
|
import org.keycloak.services.clientregistration.ErrorCodes;
|
||||||
|
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
|
@ -21,6 +23,8 @@ import java.net.URI;
|
||||||
*/
|
*/
|
||||||
public class OIDCClientRegistrationProvider extends AbstractClientRegistrationProvider {
|
public class OIDCClientRegistrationProvider extends AbstractClientRegistrationProvider {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(OIDCClientRegistrationProvider.class);
|
||||||
|
|
||||||
public OIDCClientRegistrationProvider(KeycloakSession session) {
|
public OIDCClientRegistrationProvider(KeycloakSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
}
|
}
|
||||||
|
@ -33,12 +37,17 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
|
||||||
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier included", Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier included", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
|
try {
|
||||||
client = create(client);
|
ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
|
||||||
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
|
client = create(client);
|
||||||
clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
|
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
|
||||||
clientOIDC.setClientIdIssuedAt(Time.currentTime());
|
clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
|
||||||
return Response.created(uri).entity(clientOIDC).build();
|
clientOIDC.setClientIdIssuedAt(Time.currentTime());
|
||||||
|
return Response.created(uri).entity(clientOIDC).build();
|
||||||
|
} catch (ClientRegistrationException cre) {
|
||||||
|
log.error(cre.getMessage());
|
||||||
|
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client metadata invalid", Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
@ -54,11 +63,16 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
|
||||||
@Path("{clientId}")
|
@Path("{clientId}")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public Response updateOIDC(@PathParam("clientId") String clientId, OIDCClientRepresentation clientOIDC) {
|
public Response updateOIDC(@PathParam("clientId") String clientId, OIDCClientRepresentation clientOIDC) {
|
||||||
ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
|
try {
|
||||||
client = update(clientId, client);
|
ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
|
||||||
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
|
client = update(clientId, client);
|
||||||
clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
|
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
|
||||||
return Response.ok(clientOIDC).build();
|
clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
|
||||||
|
return Response.ok(clientOIDC).build();
|
||||||
|
} catch (ClientRegistrationException cre) {
|
||||||
|
log.error(cre.getMessage());
|
||||||
|
throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client metadata invalid", Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.GroupRepresentation;
|
import org.keycloak.representations.idm.GroupRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.services.clientregistration.ClientRegistrationException;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package org.keycloak.test;
|
package org.keycloak.test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
|
@ -16,7 +19,7 @@ public class ResponseTypeTest {
|
||||||
assertFail("foo");
|
assertFail("foo");
|
||||||
assertSuccess("code");
|
assertSuccess("code");
|
||||||
assertSuccess("none");
|
assertSuccess("none");
|
||||||
assertFail("id_token");
|
assertSuccess("id_token");
|
||||||
assertFail("token");
|
assertFail("token");
|
||||||
assertFail("refresh_token");
|
assertFail("refresh_token");
|
||||||
assertSuccess("id_token token");
|
assertSuccess("id_token token");
|
||||||
|
@ -27,6 +30,38 @@ public class ResponseTypeTest {
|
||||||
assertFail("code refresh_token");
|
assertFail("code refresh_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleResponseTypes() {
|
||||||
|
try {
|
||||||
|
OIDCResponseType.parse(Arrays.asList("code", "token"));
|
||||||
|
Assert.fail("Not expected to parse with success");
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OIDCResponseType responseType = OIDCResponseType.parse(Collections.singletonList("code"));
|
||||||
|
Assert.assertTrue(responseType.hasResponseType("code"));
|
||||||
|
Assert.assertFalse(responseType.hasResponseType("none"));
|
||||||
|
Assert.assertFalse(responseType.isImplicitOrHybridFlow());
|
||||||
|
|
||||||
|
responseType = OIDCResponseType.parse(Arrays.asList("code", "none"));
|
||||||
|
Assert.assertTrue(responseType.hasResponseType("code"));
|
||||||
|
Assert.assertTrue(responseType.hasResponseType("none"));
|
||||||
|
Assert.assertFalse(responseType.isImplicitOrHybridFlow());
|
||||||
|
|
||||||
|
responseType = OIDCResponseType.parse(Arrays.asList("code", "code token"));
|
||||||
|
Assert.assertTrue(responseType.hasResponseType("code"));
|
||||||
|
Assert.assertFalse(responseType.hasResponseType("none"));
|
||||||
|
Assert.assertTrue(responseType.hasResponseType("token"));
|
||||||
|
Assert.assertFalse(responseType.hasResponseType("id_token"));
|
||||||
|
Assert.assertTrue(responseType.isImplicitOrHybridFlow());
|
||||||
|
Assert.assertFalse(responseType.isImplicitFlow());
|
||||||
|
|
||||||
|
responseType = OIDCResponseType.parse(Arrays.asList("id_token", "id_token token"));
|
||||||
|
Assert.assertFalse(responseType.hasResponseType("code"));
|
||||||
|
Assert.assertTrue(responseType.isImplicitOrHybridFlow());
|
||||||
|
Assert.assertTrue(responseType.isImplicitFlow());
|
||||||
|
}
|
||||||
|
|
||||||
private void assertSuccess(String responseType) {
|
private void assertSuccess(String responseType) {
|
||||||
OIDCResponseType.parse(responseType);
|
OIDCResponseType.parse(responseType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,16 @@ package org.keycloak.testsuite.client;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.client.registration.Auth;
|
import org.keycloak.client.registration.Auth;
|
||||||
import org.keycloak.client.registration.ClientRegistrationException;
|
import org.keycloak.client.registration.ClientRegistrationException;
|
||||||
|
import org.keycloak.common.util.CollectionUtil;
|
||||||
|
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||||
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
|
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
|
||||||
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
|
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
|
||||||
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
import org.keycloak.representations.oidc.OIDCClientRepresentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
@ -49,6 +53,8 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
assertEquals("http://root", response.getClientUri());
|
assertEquals("http://root", response.getClientUri());
|
||||||
assertEquals(1, response.getRedirectUris().size());
|
assertEquals(1, response.getRedirectUris().size());
|
||||||
assertEquals("http://redirect", response.getRedirectUris().get(0));
|
assertEquals("http://redirect", response.getRedirectUris().get(0));
|
||||||
|
assertEquals(Arrays.asList("code", "none"), response.getResponseTypes());
|
||||||
|
assertEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -59,6 +65,8 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
OIDCClientRepresentation rep = reg.oidc().get(response.getClientId());
|
OIDCClientRepresentation rep = reg.oidc().get(response.getClientId());
|
||||||
assertNotNull(rep);
|
assertNotNull(rep);
|
||||||
assertNotEquals(response.getRegistrationAccessToken(), rep.getRegistrationAccessToken());
|
assertNotEquals(response.getRegistrationAccessToken(), rep.getRegistrationAccessToken());
|
||||||
|
assertTrue(CollectionUtil.collectionEquals(Arrays.asList("code", "none"), response.getResponseTypes()));
|
||||||
|
assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -67,11 +75,26 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
reg.auth(Auth.token(response));
|
reg.auth(Auth.token(response));
|
||||||
|
|
||||||
response.setRedirectUris(Collections.singletonList("http://newredirect"));
|
response.setRedirectUris(Collections.singletonList("http://newredirect"));
|
||||||
|
response.setResponseTypes(Arrays.asList("code", "id_token token", "code id_token token"));
|
||||||
|
response.setGrantTypes(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD));
|
||||||
|
|
||||||
OIDCClientRepresentation updated = reg.oidc().update(response);
|
OIDCClientRepresentation updated = reg.oidc().update(response);
|
||||||
|
|
||||||
assertEquals(1, updated.getRedirectUris().size());
|
assertTrue(CollectionUtil.collectionEquals(Collections.singletonList("http://newredirect"), updated.getRedirectUris()));
|
||||||
assertEquals("http://newredirect", updated.getRedirectUris().get(0));
|
assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD), updated.getGrantTypes()));
|
||||||
|
assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token"), updated.getResponseTypes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateClientError() throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
OIDCClientRepresentation response = create();
|
||||||
|
reg.auth(Auth.token(response));
|
||||||
|
response.setResponseTypes(Arrays.asList("code", "token"));
|
||||||
|
reg.oidc().update(response);
|
||||||
|
fail("Not expected to end with success");
|
||||||
|
} catch (ClientRegistrationException cre) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
|
||||||
return expect(EventType.CLIENT_LOGIN)
|
return expect(EventType.CLIENT_LOGIN)
|
||||||
.detail(Details.CODE_ID, isCodeId())
|
.detail(Details.CODE_ID, isCodeId())
|
||||||
.detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
|
.detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
|
||||||
.removeDetail(Details.CODE_ID)
|
.removeDetail(Details.CODE_ID)
|
||||||
.session(isUUID());
|
.session(isUUID());
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ public class CustomFlowTest {
|
||||||
.client(clientId)
|
.client(clientId)
|
||||||
.user(userId)
|
.user(userId)
|
||||||
.session(accessToken.getSessionState())
|
.session(accessToken.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, accessToken.getId())
|
.detail(Details.TOKEN_ID, accessToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
||||||
.detail(Details.USERNAME, login)
|
.detail(Details.USERNAME, login)
|
||||||
|
|
|
@ -257,7 +257,7 @@ public class GroupTest {
|
||||||
.client(clientId)
|
.client(clientId)
|
||||||
.user(userId)
|
.user(userId)
|
||||||
.session(accessToken.getSessionState())
|
.session(accessToken.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, accessToken.getId())
|
.detail(Details.TOKEN_ID, accessToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
||||||
.detail(Details.USERNAME, login)
|
.detail(Details.USERNAME, login)
|
||||||
|
|
|
@ -189,7 +189,7 @@ public class ClientAuthSignedJWTTest {
|
||||||
events.expectLogin()
|
events.expectLogin()
|
||||||
.client("client2")
|
.client("client2")
|
||||||
.session(accessToken.getSessionState())
|
.session(accessToken.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, accessToken.getId())
|
.detail(Details.TOKEN_ID, accessToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
||||||
.detail(Details.USERNAME, "test-user@localhost")
|
.detail(Details.USERNAME, "test-user@localhost")
|
||||||
|
|
|
@ -319,7 +319,7 @@ public class OfflineTokenTest {
|
||||||
.client("offline-client")
|
.client("offline-client")
|
||||||
.user(userId)
|
.user(userId)
|
||||||
.session(token.getSessionState())
|
.session(token.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, token.getId())
|
.detail(Details.TOKEN_ID, token.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
|
.detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
|
||||||
|
@ -361,7 +361,7 @@ public class OfflineTokenTest {
|
||||||
.client("offline-client")
|
.client("offline-client")
|
||||||
.user(userId)
|
.user(userId)
|
||||||
.session(token.getSessionState())
|
.session(token.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, token.getId())
|
.detail(Details.TOKEN_ID, token.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
|
.detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
|
||||||
.client(clientId)
|
.client(clientId)
|
||||||
.user(userId)
|
.user(userId)
|
||||||
.session(accessToken.getSessionState())
|
.session(accessToken.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, accessToken.getId())
|
.detail(Details.TOKEN_ID, accessToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
||||||
.detail(Details.USERNAME, login)
|
.detail(Details.USERNAME, login)
|
||||||
|
@ -130,7 +130,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
|
||||||
events.expectLogin()
|
events.expectLogin()
|
||||||
.client("resource-owner")
|
.client("resource-owner")
|
||||||
.session(accessToken.getSessionState())
|
.session(accessToken.getSessionState())
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.TOKEN_ID, accessToken.getId())
|
.detail(Details.TOKEN_ID, accessToken.getId())
|
||||||
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
|
||||||
.removeDetail(Details.CODE_ID)
|
.removeDetail(Details.CODE_ID)
|
||||||
|
@ -286,7 +286,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
|
||||||
events.expectLogin()
|
events.expectLogin()
|
||||||
.client("resource-owner")
|
.client("resource-owner")
|
||||||
.session((String) null)
|
.session((String) null)
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.removeDetail(Details.CODE_ID)
|
.removeDetail(Details.CODE_ID)
|
||||||
.removeDetail(Details.REDIRECT_URI)
|
.removeDetail(Details.REDIRECT_URI)
|
||||||
.removeDetail(Details.CONSENT)
|
.removeDetail(Details.CONSENT)
|
||||||
|
@ -308,7 +308,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
|
||||||
.client("resource-owner")
|
.client("resource-owner")
|
||||||
.user((String) null)
|
.user((String) null)
|
||||||
.session((String) null)
|
.session((String) null)
|
||||||
.detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
|
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
|
||||||
.detail(Details.USERNAME, "invalid")
|
.detail(Details.USERNAME, "invalid")
|
||||||
.removeDetail(Details.CODE_ID)
|
.removeDetail(Details.CODE_ID)
|
||||||
.removeDetail(Details.REDIRECT_URI)
|
.removeDetail(Details.REDIRECT_URI)
|
||||||
|
|
Loading…
Reference in a new issue