FAPI 2.0 security profile - supporting RFC 9207 OAuth 2.0 Authorization Server Issuer Identification
Closes #20584
This commit is contained in:
parent
821316a61a
commit
2efd79f982
28 changed files with 318 additions and 38 deletions
|
@ -384,7 +384,8 @@ public class OAuthRequestAuthenticator {
|
||||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(facade.getRequest().getURI())
|
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(facade.getRequest().getURI())
|
||||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||||
.replaceQueryParam(OAuth2Constants.STATE, null)
|
.replaceQueryParam(OAuth2Constants.STATE, null)
|
||||||
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null);
|
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null)
|
||||||
|
.replaceQueryParam(OAuth2Constants.ISSUER, null);
|
||||||
return builder.buildAsString();
|
return builder.buildAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,8 @@ public class ServerRequest {
|
||||||
protected static String stripOauthParametersFromRedirect(String uri) {
|
protected static String stripOauthParametersFromRedirect(String uri) {
|
||||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
||||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||||
.replaceQueryParam(OAuth2Constants.STATE, null);
|
.replaceQueryParam(OAuth2Constants.STATE, null)
|
||||||
|
.replaceQueryParam(OAuth2Constants.ISSUER, null);
|
||||||
return builder.buildAsString();
|
return builder.buildAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,9 @@ public interface OAuth2Constants {
|
||||||
|
|
||||||
// https://openid.net/specs/openid-financial-api-jarm-ID1.html
|
// https://openid.net/specs/openid-financial-api-jarm-ID1.html
|
||||||
String RESPONSE = "response";
|
String RESPONSE = "response";
|
||||||
|
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc9207.html
|
||||||
|
String ISSUER = "iss";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,9 @@ public class OIDCConfigurationRepresentation {
|
||||||
@JsonProperty("mtls_endpoint_aliases")
|
@JsonProperty("mtls_endpoint_aliases")
|
||||||
private MTLSEndpointAliases mtlsEndpointAliases;
|
private MTLSEndpointAliases mtlsEndpointAliases;
|
||||||
|
|
||||||
|
@JsonProperty("authorization_response_iss_parameter_supported")
|
||||||
|
private Boolean authorizationResponseIssParameterSupported;
|
||||||
|
|
||||||
protected Map<String, Object> otherClaims = new HashMap<String, Object>();
|
protected Map<String, Object> otherClaims = new HashMap<String, Object>();
|
||||||
|
|
||||||
public String getIssuer() {
|
public String getIssuer() {
|
||||||
|
@ -624,4 +627,13 @@ public class OIDCConfigurationRepresentation {
|
||||||
public Boolean getFrontChannelLogoutSupported() {
|
public Boolean getFrontChannelLogoutSupported() {
|
||||||
return frontChannelLogoutSupported;
|
return frontChannelLogoutSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getAuthorizationResponseIssParameterSupported() {
|
||||||
|
return authorizationResponseIssParameterSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthorizationResponseIssParameterSupported(Boolean authorizationResponseIssParameterSupported) {
|
||||||
|
this.authorizationResponseIssParameterSupported = authorizationResponseIssParameterSupported;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
= Added iss parameter to OAuth 2.0/OpenID Connect Authentication Response
|
||||||
|
|
||||||
|
RFC 9207 OAuth 2.0 Authorization Server Issuer Identification specification adds the parameter `iss` in the OAuth 2.0/OpenID Connect Authentication Response for realizing secure authorization responses.
|
||||||
|
|
||||||
|
In past releases, we did not have this parameter, but now {project_name} adds this parameter by default, as required by the specification.
|
||||||
|
|
||||||
|
However, some OpenID Connect / OAuth2 adapters, and especially older {project_name} adapters, may have issues with this new parameter.
|
||||||
|
|
||||||
|
For example, the parameter will be always present in the browser URL after successful authentication to the client application.
|
||||||
|
In these cases, it may be useful to disable adding the `iss` parameter to the authentication response. This can be done
|
||||||
|
for the particular client in the {project_name} Admin console, in client details in the section with `OpenID Connect Compatibility Modes`,
|
||||||
|
described in <<_compatibility_with_older_adapters>>. Dedicated `Exclude Issuer From Authentication Response` switch exists,
|
||||||
|
which can be turned on to prevent adding the `iss` parameter to the authentication response.
|
|
@ -1,5 +1,9 @@
|
||||||
== Migration Changes
|
== Migration Changes
|
||||||
|
|
||||||
|
=== Migrating to 23.0.0
|
||||||
|
|
||||||
|
include::changes-23_0_0.adoc[leveloffset=3]
|
||||||
|
|
||||||
=== Migrating to 22.0.0
|
=== Migrating to 22.0.0
|
||||||
|
|
||||||
include::changes-22_0_0.adoc[leveloffset=3]
|
include::changes-22_0_0.adoc[leveloffset=3]
|
||||||
|
|
|
@ -96,6 +96,7 @@
|
||||||
"authorizationEncryptedResponseEnc": "JWA Algorithm used for content encryption in encrypting the authorization response when the response mode is jwt. This option is needed if you want encrypted authorization response. If left empty, the authorization response is just signed, but not encrypted.",
|
"authorizationEncryptedResponseEnc": "JWA Algorithm used for content encryption in encrypting the authorization response when the response mode is jwt. This option is needed if you want encrypted authorization response. If left empty, the authorization response is just signed, but not encrypted.",
|
||||||
"openIdConnectCompatibilityModes": "This section is used to configure settings for backward compatibility with older OpenID Connect / OAuth 2 adaptors. It's useful especially if your client uses older version of Keycloak / RH-SSO adapter.",
|
"openIdConnectCompatibilityModes": "This section is used to configure settings for backward compatibility with older OpenID Connect / OAuth 2 adaptors. It's useful especially if your client uses older version of Keycloak / RH-SSO adapter.",
|
||||||
"excludeSessionStateFromAuthenticationResponse": "If this is on, the parameter 'session_state' will not be included in OpenID Connect Authentication Response. It is useful if your client uses older OIDC / OAuth2 adapter, which does not support 'session_state' parameter.",
|
"excludeSessionStateFromAuthenticationResponse": "If this is on, the parameter 'session_state' will not be included in OpenID Connect Authentication Response. It is useful if your client uses older OIDC / OAuth2 adapter, which does not support 'session_state' parameter.",
|
||||||
|
"excludeIssuerFromAuthenticationResponse": "If this is on, the parameter 'iss' will not be included in OpenID Connect Authentication Response. It is useful if your client uses older OIDC / OAuth2 adapter, which does not support 'session_state' parameter.",
|
||||||
"useRefreshTokens": "If this is on, a refresh_token will be created and added to the token response. If this is off then no refresh_token will be generated.",
|
"useRefreshTokens": "If this is on, a refresh_token will be created and added to the token response. If this is off then no refresh_token will be generated.",
|
||||||
"useRefreshTokenForClientCredentialsGrant": "If this is on, a refresh_token will be created and added to the token response if the client_credentials grant is used. The OAuth 2.0 RFC6749 Section 4.4.3 states that a refresh_token should not be generated when client_credentials grant is used. If this is off then no refresh_token will be generated and the associated user session will be removed.",
|
"useRefreshTokenForClientCredentialsGrant": "If this is on, a refresh_token will be created and added to the token response if the client_credentials grant is used. The OAuth 2.0 RFC6749 Section 4.4.3 states that a refresh_token should not be generated when client_credentials grant is used. If this is off then no refresh_token will be generated and the associated user session will be removed.",
|
||||||
"useLowerCaseBearerType": "If this is on, token responses will be set the with the type \"bearer\" in lower-case. By default, the server sets the type as \"Bearer\" as defined by RFC6750.",
|
"useLowerCaseBearerType": "If this is on, token responses will be set the with the type \"bearer\" in lower-case. By default, the server sets the type as \"Bearer\" as defined by RFC6750.",
|
||||||
|
|
|
@ -492,6 +492,7 @@
|
||||||
"authorizationEncryptedResponseEnc": "Authorization response encryption content encryption algorithm",
|
"authorizationEncryptedResponseEnc": "Authorization response encryption content encryption algorithm",
|
||||||
"openIdConnectCompatibilityModes": "Open ID Connect Compatibility Modes",
|
"openIdConnectCompatibilityModes": "Open ID Connect Compatibility Modes",
|
||||||
"excludeSessionStateFromAuthenticationResponse": "Exclude Session State From Authentication Response",
|
"excludeSessionStateFromAuthenticationResponse": "Exclude Session State From Authentication Response",
|
||||||
|
"excludeIssuerFromAuthenticationResponse": "Exclude Issuer From Authentication Response",
|
||||||
"useRefreshTokens": "Use refresh tokens",
|
"useRefreshTokens": "Use refresh tokens",
|
||||||
"useRefreshTokenForClientCredentialsGrant": "Use refresh tokens for client credentials grant",
|
"useRefreshTokenForClientCredentialsGrant": "Use refresh tokens for client credentials grant",
|
||||||
"useLowerCaseBearerType": "Use lower-case bearer type in token responses",
|
"useLowerCaseBearerType": "Use lower-case bearer type in token responses",
|
||||||
|
|
|
@ -57,6 +57,35 @@ export const OpenIdConnectCompatibilityModes = ({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("excludeIssuerFromAuthenticationResponse")}
|
||||||
|
fieldId="excludeIssuerFromAuthenticationResponse"
|
||||||
|
hasNoPaddingTop
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("clients-help:excludeIssuerFromAuthenticationResponse")}
|
||||||
|
fieldLabelId="clients:excludeIssuerFromAuthenticationResponse"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name={convertAttributeNameToForm<FormFields>(
|
||||||
|
"attributes.exclude.issuer.from.auth.response",
|
||||||
|
)}
|
||||||
|
defaultValue=""
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<Switch
|
||||||
|
id="excludeIssuerFromAuthenticationResponse-switch"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={field.value === "true"}
|
||||||
|
onChange={(value) => field.onChange(value.toString())}
|
||||||
|
aria-label={t("excludeIssuerFromAuthenticationResponse")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("useRefreshTokens")}
|
label={t("useRefreshTokens")}
|
||||||
fieldId="useRefreshTokens"
|
fieldId="useRefreshTokens"
|
||||||
|
|
|
@ -1077,13 +1077,13 @@ function Keycloak (config) {
|
||||||
var supportedParams;
|
var supportedParams;
|
||||||
switch (kc.flow) {
|
switch (kc.flow) {
|
||||||
case 'standard':
|
case 'standard':
|
||||||
supportedParams = ['code', 'state', 'session_state', 'kc_action_status'];
|
supportedParams = ['code', 'state', 'session_state', 'kc_action_status', 'iss'];
|
||||||
break;
|
break;
|
||||||
case 'implicit':
|
case 'implicit':
|
||||||
supportedParams = ['access_token', 'token_type', 'id_token', 'state', 'session_state', 'expires_in', 'kc_action_status'];
|
supportedParams = ['access_token', 'token_type', 'id_token', 'state', 'session_state', 'expires_in', 'kc_action_status', 'iss'];
|
||||||
break;
|
break;
|
||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
supportedParams = ['access_token', 'token_type', 'id_token', 'code', 'state', 'session_state', 'expires_in', 'kc_action_status'];
|
supportedParams = ['access_token', 'token_type', 'id_token', 'code', 'state', 'session_state', 'expires_in', 'kc_action_status', 'iss'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ public final class OIDCConfigAttributes {
|
||||||
public static final String USE_JWKS_STRING = "use.jwks.string";
|
public static final String USE_JWKS_STRING = "use.jwks.string";
|
||||||
|
|
||||||
public static final String EXCLUDE_SESSION_STATE_FROM_AUTH_RESPONSE = "exclude.session.state.from.auth.response";
|
public static final String EXCLUDE_SESSION_STATE_FROM_AUTH_RESPONSE = "exclude.session.state.from.auth.response";
|
||||||
|
public static final String EXCLUDE_ISSUER_FROM_AUTH_RESPONSE = "exclude.issuer.from.auth.response";
|
||||||
|
|
||||||
public static final String USE_MTLS_HOK_TOKEN = "tls.client.certificate.bound.access.tokens";
|
public static final String USE_MTLS_HOK_TOKEN = "tls.client.certificate.bound.access.tokens";
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,16 @@ public class OIDCAdvancedConfigWrapper extends AbstractClientConfigWrapper {
|
||||||
setAttribute(OIDCConfigAttributes.EXCLUDE_SESSION_STATE_FROM_AUTH_RESPONSE, val);
|
setAttribute(OIDCConfigAttributes.EXCLUDE_SESSION_STATE_FROM_AUTH_RESPONSE, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isExcludeIssuerFromAuthResponse() {
|
||||||
|
String excludeIssuerFromAuthResponse = getAttribute(OIDCConfigAttributes.EXCLUDE_ISSUER_FROM_AUTH_RESPONSE);
|
||||||
|
return Boolean.parseBoolean(excludeIssuerFromAuthResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeIssuerFromAuthResponse(boolean excludeIssuerFromAuthResponse) {
|
||||||
|
String val = String.valueOf(excludeIssuerFromAuthResponse);
|
||||||
|
setAttribute(OIDCConfigAttributes.EXCLUDE_ISSUER_FROM_AUTH_RESPONSE, val);
|
||||||
|
}
|
||||||
|
|
||||||
// KEYCLOAK-6771 Certificate Bound Token
|
// KEYCLOAK-6771 Certificate Bound Token
|
||||||
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.5
|
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.5
|
||||||
public boolean isUseMtlsHokToken() {
|
public boolean isUseMtlsHokToken() {
|
||||||
|
|
|
@ -223,6 +223,9 @@ public class OIDCLoginProtocol implements LoginProtocol {
|
||||||
if (!clientConfig.isExcludeSessionStateFromAuthResponse()) {
|
if (!clientConfig.isExcludeSessionStateFromAuthResponse()) {
|
||||||
redirectUri.addParam(OAuth2Constants.SESSION_STATE, userSession.getId());
|
redirectUri.addParam(OAuth2Constants.SESSION_STATE, userSession.getId());
|
||||||
}
|
}
|
||||||
|
if (!clientConfig.isExcludeIssuerFromAuthResponse()) {
|
||||||
|
redirectUri.addParam(OAuth2Constants.ISSUER, clientSession.getNote(OIDCLoginProtocol.ISSUER));
|
||||||
|
}
|
||||||
|
|
||||||
String nonce = authSession.getClientNote(OIDCLoginProtocol.NONCE_PARAM);
|
String nonce = authSession.getClientNote(OIDCLoginProtocol.NONCE_PARAM);
|
||||||
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, nonce);
|
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, nonce);
|
||||||
|
@ -278,6 +281,9 @@ public class OIDCLoginProtocol implements LoginProtocol {
|
||||||
event.error(cpe.getError());
|
event.error(cpe.getError());
|
||||||
new AuthenticationSessionManager(session).removeAuthenticationSession(realm, authSession, true);
|
new AuthenticationSessionManager(session).removeAuthenticationSession(realm, authSession, true);
|
||||||
redirectUri.addParam(OAuth2Constants.ERROR_DESCRIPTION, cpe.getError());
|
redirectUri.addParam(OAuth2Constants.ERROR_DESCRIPTION, cpe.getError());
|
||||||
|
if (!clientConfig.isExcludeIssuerFromAuthResponse()) {
|
||||||
|
redirectUri.addParam(OAuth2Constants.ISSUER, clientSession.getNote(OIDCLoginProtocol.ISSUER));
|
||||||
|
}
|
||||||
return redirectUri.build();
|
return redirectUri.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,8 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
|
||||||
MTLSEndpointAliases mtlsEndpointAliases = getMtlsEndpointAliases(config);
|
MTLSEndpointAliases mtlsEndpointAliases = getMtlsEndpointAliases(config);
|
||||||
config.setMtlsEndpointAliases(mtlsEndpointAliases);
|
config.setMtlsEndpointAliases(mtlsEndpointAliases);
|
||||||
|
|
||||||
|
config.setAuthorizationResponseIssParameterSupported(true);
|
||||||
|
|
||||||
config = checkConfigOverride(config);
|
config = checkConfigOverride(config);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.AuthorizationEndpointBase;
|
import org.keycloak.protocol.AuthorizationEndpointBase;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequestParserProcessor;
|
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequestParserProcessor;
|
||||||
|
@ -300,6 +301,11 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
|
||||||
errorResponseBuilder.addParam(OAuth2Constants.STATE, request.getState());
|
errorResponseBuilder.addParam(OAuth2Constants.STATE, request.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OIDCAdvancedConfigWrapper clientConfig = OIDCAdvancedConfigWrapper.fromClientModel(client);
|
||||||
|
if (!clientConfig.isExcludeIssuerFromAuthResponse()) {
|
||||||
|
errorResponseBuilder.addParam(OAuth2Constants.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
return errorResponseBuilder.build();
|
return errorResponseBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,10 @@
|
||||||
"redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
|
"redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
|
||||||
"baseUrl": "http://localhost:8080/hello-world-authz-service",
|
"baseUrl": "http://localhost:8080/hello-world-authz-service",
|
||||||
"adminUrl": "http://localhost:8080/hello-world-authz-service",
|
"adminUrl": "http://localhost:8080/hello-world-authz-service",
|
||||||
"directAccessGrantsEnabled" : true
|
"directAccessGrantsEnabled" : true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -88,7 +88,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/servlet-authz-app/*"
|
"/servlet-authz-app/*"
|
||||||
],
|
],
|
||||||
"secret": "secret"
|
"secret": "secret",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,6 +338,9 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scopes": []
|
"scopes": []
|
||||||
|
},
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1798,6 +1798,8 @@ public class OAuthClient {
|
||||||
// Just during FAPI JARM response mode JWT
|
// Just during FAPI JARM response mode JWT
|
||||||
private String response;
|
private String response;
|
||||||
|
|
||||||
|
private String issuer;
|
||||||
|
|
||||||
public AuthorizationEndpointResponse(OAuthClient client) {
|
public AuthorizationEndpointResponse(OAuthClient client) {
|
||||||
boolean fragment;
|
boolean fragment;
|
||||||
if (client.responseMode == null || "jwt".equals(client.responseMode)) {
|
if (client.responseMode == null || "jwt".equals(client.responseMode)) {
|
||||||
|
@ -1830,6 +1832,7 @@ public class OAuthClient {
|
||||||
tokenType = params.get(OAuth2Constants.TOKEN_TYPE);
|
tokenType = params.get(OAuth2Constants.TOKEN_TYPE);
|
||||||
expiresIn = params.get(OAuth2Constants.EXPIRES_IN);
|
expiresIn = params.get(OAuth2Constants.EXPIRES_IN);
|
||||||
response = params.get(OAuth2Constants.RESPONSE);
|
response = params.get(OAuth2Constants.RESPONSE);
|
||||||
|
issuer = params.get(OAuth2Constants.ISSUER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRedirected() {
|
public boolean isRedirected() {
|
||||||
|
@ -1875,6 +1878,9 @@ public class OAuthClient {
|
||||||
public String getResponse() {
|
public String getResponse() {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AuthenticationRequestAcknowledgement {
|
public static class AuthenticationRequestAcknowledgement {
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
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.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
@ -77,8 +78,11 @@ import jakarta.ws.rs.core.Response;
|
||||||
import jakarta.ws.rs.core.UriBuilder;
|
import jakarta.ws.rs.core.UriBuilder;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
|
import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
|
||||||
|
|
||||||
|
@ -159,6 +163,11 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest
|
||||||
servlet.getRedirectUris().add(uri + "/*");
|
servlet.getRedirectUris().add(uri + "/*");
|
||||||
servlet.setSecret("password");
|
servlet.setSecret("password");
|
||||||
servlet.setFullScopeAllowed(true);
|
servlet.setFullScopeAllowed(true);
|
||||||
|
|
||||||
|
Map<String, String> attributes = Optional.ofNullable(servlet.getAttributes()).orElse(new HashMap<>());
|
||||||
|
attributes.put(OIDCConfigAttributes.EXCLUDE_ISSUER_FROM_AUTH_RESPONSE, Boolean.TRUE.toString());
|
||||||
|
servlet.setAttributes(attributes);
|
||||||
|
|
||||||
realm.setClients(new LinkedList<>());
|
realm.setClients(new LinkedList<>());
|
||||||
realm.getClients().add(servlet);
|
realm.getClients().add(servlet);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.keycloak.common.util.Base64Url;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
@ -61,6 +62,7 @@ import org.keycloak.util.JsonSerialization;
|
||||||
import jakarta.ws.rs.client.Client;
|
import jakarta.ws.rs.client.Client;
|
||||||
import jakarta.ws.rs.core.UriBuilder;
|
import jakarta.ws.rs.core.UriBuilder;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -138,6 +140,11 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
||||||
servlet.getRedirectUris().add(uri + "/*");
|
servlet.getRedirectUris().add(uri + "/*");
|
||||||
servlet.setSecret("password");
|
servlet.setSecret("password");
|
||||||
servlet.setFullScopeAllowed(true);
|
servlet.setFullScopeAllowed(true);
|
||||||
|
|
||||||
|
Map<String, String> attributes = Optional.ofNullable(servlet.getAttributes()).orElse(new HashMap<>());
|
||||||
|
attributes.put(OIDCConfigAttributes.EXCLUDE_ISSUER_FROM_AUTH_RESPONSE, Boolean.TRUE.toString());
|
||||||
|
servlet.setAttributes(attributes);
|
||||||
|
|
||||||
realm.setClients(new LinkedList<>());
|
realm.setClients(new LinkedList<>());
|
||||||
realm.getClients().add(servlet);
|
realm.getClients().add(servlet);
|
||||||
testRealms.add(realm);
|
testRealms.add(realm);
|
||||||
|
|
|
@ -86,6 +86,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
|
||||||
Assert.assertNotNull(response.getCode());
|
Assert.assertNotNull(response.getCode());
|
||||||
assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", response.getState());
|
assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", response.getState());
|
||||||
Assert.assertNull(response.getError());
|
Assert.assertNull(response.getError());
|
||||||
|
assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", response.getIssuer());
|
||||||
|
|
||||||
String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID);
|
String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID);
|
||||||
}
|
}
|
||||||
|
@ -160,6 +161,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
|
||||||
Assert.assertNotNull(response.getCode());
|
Assert.assertNotNull(response.getCode());
|
||||||
Assert.assertNull(response.getState());
|
Assert.assertNull(response.getState());
|
||||||
Assert.assertNull(response.getError());
|
Assert.assertNull(response.getError());
|
||||||
|
assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", response.getIssuer());
|
||||||
|
|
||||||
String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID);
|
String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID);
|
||||||
}
|
}
|
||||||
|
@ -173,6 +175,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
|
||||||
OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
|
OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
|
||||||
assertTrue(errorResponse.isRedirected());
|
assertTrue(errorResponse.isRedirected());
|
||||||
Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
|
Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
|
||||||
|
Assert.assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", errorResponse.getIssuer());
|
||||||
|
|
||||||
events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
|
events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
|
||||||
}
|
}
|
||||||
|
@ -284,6 +287,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
Assert.assertNotNull(response.getCode());
|
Assert.assertNotNull(response.getCode());
|
||||||
Assert.assertNotNull(response.getState());
|
Assert.assertNotNull(response.getState());
|
||||||
|
Assert.assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", response.getIssuer());
|
||||||
|
|
||||||
currentUri = new URI(driver.getCurrentUrl());
|
currentUri = new URI(driver.getCurrentUrl());
|
||||||
Assert.assertNotNull(currentUri.getRawQuery());
|
Assert.assertNotNull(currentUri.getRawQuery());
|
||||||
|
|
|
@ -501,6 +501,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
|
||||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||||
.replaceQueryParam(OAuth2Constants.STATE, null)
|
.replaceQueryParam(OAuth2Constants.STATE, null)
|
||||||
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null)
|
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null)
|
||||||
|
.replaceQueryParam(OAuth2Constants.ISSUER, null)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
if (browserUrlAfterRedirectFromKeycloak.endsWith("/")) browserUrlAfterRedirectFromKeycloak = browserUrlAfterRedirectFromKeycloak.substring(0, browserUrlAfterRedirectFromKeycloak.length() - 1);
|
if (browserUrlAfterRedirectFromKeycloak.endsWith("/")) browserUrlAfterRedirectFromKeycloak = browserUrlAfterRedirectFromKeycloak.substring(0, browserUrlAfterRedirectFromKeycloak.length() - 1);
|
||||||
if (Constants.INSTALLED_APP_URN.equals(redirectUri)) {
|
if (Constants.INSTALLED_APP_URN.equals(redirectUri)) {
|
||||||
|
|
|
@ -17,12 +17,18 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.oidc;
|
package org.keycloak.testsuite.oidc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.OAuthErrorException;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
|
import org.keycloak.events.Errors;
|
||||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.EventRepresentation;
|
import org.keycloak.representations.idm.EventRepresentation;
|
||||||
|
@ -38,6 +44,8 @@ import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||||
import org.keycloak.testsuite.util.ClientManager;
|
import org.keycloak.testsuite.util.ClientManager;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.core.UriBuilder;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -106,5 +114,64 @@ public class OIDCBackwardsCompatibilityTest extends AbstractTestRealmKeycloakTes
|
||||||
client.update(clientRep);
|
client.update(clientRep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExcludeIssuerParameter() {
|
||||||
|
// Open login form and login successfully. Assert iss parameter is present
|
||||||
|
OAuthClient.AuthorizationEndpointResponse authzResponse = oauth.doLogin("test-user@localhost", "password");
|
||||||
|
events.expectLogin().assertEvent();
|
||||||
|
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
Assert.assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", authzResponse.getIssuer());
|
||||||
|
|
||||||
|
// Switch "exclude iss" to on
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
|
||||||
|
ClientRepresentation clientRep = client.toRepresentation();
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep);
|
||||||
|
config.setExcludeIssuerFromAuthResponse(true);
|
||||||
|
client.update(clientRep);
|
||||||
|
|
||||||
|
// Open login again and assert iss parameter is not present
|
||||||
|
driver.navigate().to(oauth.getLoginFormUrl());
|
||||||
|
org.keycloak.testsuite.Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
|
||||||
|
|
||||||
|
authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
|
||||||
|
Assert.assertNull(authzResponse.getIssuer());
|
||||||
|
|
||||||
|
// Revert
|
||||||
|
config.setExcludeIssuerFromAuthResponse(false);
|
||||||
|
client.update(clientRep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExcludeIssuerParameterOnError() throws IOException {
|
||||||
|
// Open login form and login fails. Assert iss parameter is present
|
||||||
|
oauth.responseType("tokenn");
|
||||||
|
UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
|
||||||
|
driver.navigate().to(b.build().toURL());
|
||||||
|
|
||||||
|
OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
|
||||||
|
assertTrue(errorResponse.isRedirected());
|
||||||
|
Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
|
||||||
|
Assert.assertEquals(oauth.AUTH_SERVER_ROOT + "/realms/test", errorResponse.getIssuer());
|
||||||
|
|
||||||
|
events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
|
||||||
|
|
||||||
|
// Switch "exclude iss" to on
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
|
||||||
|
ClientRepresentation clientRep = client.toRepresentation();
|
||||||
|
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep);
|
||||||
|
config.setExcludeIssuerFromAuthResponse(true);
|
||||||
|
client.update(clientRep);
|
||||||
|
|
||||||
|
// Open login again and assert iss parameter is not present
|
||||||
|
driver.navigate().to(b.build().toURL());
|
||||||
|
|
||||||
|
errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
|
||||||
|
assertTrue(errorResponse.isRedirected());
|
||||||
|
Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
|
||||||
|
Assert.assertNull(errorResponse.getIssuer());
|
||||||
|
|
||||||
|
events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -131,14 +131,20 @@
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "/customer-db",
|
"adminUrl": "/customer-db",
|
||||||
"baseUrl": "/customer-db",
|
"baseUrl": "/customer-db",
|
||||||
"bearerOnly": true
|
"bearerOnly": true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-db-audience-required",
|
"clientId": "customer-db-audience-required",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "/customer-db-audience-required",
|
"adminUrl": "/customer-db-audience-required",
|
||||||
"baseUrl": "/customer-db-audience-required",
|
"baseUrl": "/customer-db-audience-required",
|
||||||
"bearerOnly": true
|
"bearerOnly": true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-portal",
|
"clientId": "customer-portal",
|
||||||
|
@ -149,7 +155,10 @@
|
||||||
"/customer-portal/*"
|
"/customer-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "password",
|
"secret": "password",
|
||||||
"directAccessGrantsEnabled": true
|
"directAccessGrantsEnabled": true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "serialization-servlet",
|
"clientId": "serialization-servlet",
|
||||||
|
@ -160,7 +169,10 @@
|
||||||
"/serialization-servlet/*"
|
"/serialization-servlet/*"
|
||||||
],
|
],
|
||||||
"secret": "password",
|
"secret": "password",
|
||||||
"directAccessGrantsEnabled": true
|
"directAccessGrantsEnabled": true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-portal-subsystem",
|
"clientId": "customer-portal-subsystem",
|
||||||
|
@ -170,7 +182,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/customer-portal-subsystem/*"
|
"/customer-portal-subsystem/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-cookie-portal",
|
"clientId": "customer-cookie-portal",
|
||||||
|
@ -179,7 +194,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/customer-cookie-portal/*"
|
"/customer-cookie-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-cookie-portal-root",
|
"clientId": "customer-cookie-portal-root",
|
||||||
|
@ -188,7 +206,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:8080/*"
|
"http://localhost:8080/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-portal-js",
|
"clientId": "customer-portal-js",
|
||||||
|
@ -198,7 +219,10 @@
|
||||||
"baseUrl": "/customer-portal-js",
|
"baseUrl": "/customer-portal-js",
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/customer-portal-js/*"
|
"/customer-portal-js/*"
|
||||||
]
|
],
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-portal-cli",
|
"clientId": "customer-portal-cli",
|
||||||
|
@ -207,13 +231,19 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"urn:ietf:wg:oauth:2.0:oob",
|
"urn:ietf:wg:oauth:2.0:oob",
|
||||||
"http://localhost"
|
"http://localhost"
|
||||||
]
|
],
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "customer-portal-public",
|
"clientId": "customer-portal-public",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"publicClient": true,
|
"publicClient": true,
|
||||||
"directAccessGrantsEnabled": true
|
"directAccessGrantsEnabled": true,
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "product-portal",
|
"clientId": "product-portal",
|
||||||
|
@ -223,7 +253,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/product-portal/*"
|
"/product-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "product-portal-subsystem",
|
"clientId": "product-portal-subsystem",
|
||||||
|
@ -233,7 +266,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/product-portal-subsystem/*"
|
"/product-portal-subsystem/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "product-portal-autodetect-bearer-only",
|
"clientId": "product-portal-autodetect-bearer-only",
|
||||||
|
@ -243,7 +279,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/product-portal-autodetect-bearer-only/*"
|
"/product-portal-autodetect-bearer-only/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "secure-portal",
|
"clientId": "secure-portal",
|
||||||
|
@ -255,7 +294,8 @@
|
||||||
"/secure-portal/*"
|
"/secure-portal/*"
|
||||||
],
|
],
|
||||||
"attributes" : {
|
"attributes" : {
|
||||||
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg==",
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -268,7 +308,8 @@
|
||||||
"/rewritten/*"
|
"/rewritten/*"
|
||||||
],
|
],
|
||||||
"attributes" : {
|
"attributes" : {
|
||||||
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg==",
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -281,7 +322,8 @@
|
||||||
"/secure-portal-with-custom-session-config/*"
|
"/secure-portal-with-custom-session-config/*"
|
||||||
],
|
],
|
||||||
"attributes" : {
|
"attributes" : {
|
||||||
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg==",
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -292,7 +334,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/session-portal/*"
|
"/session-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "session-portal-distributable",
|
"clientId": "session-portal-distributable",
|
||||||
|
@ -302,7 +347,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:8580/session-portal-distributable/*"
|
"http://localhost:8580/session-portal-distributable/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "input-portal",
|
"clientId": "input-portal",
|
||||||
|
@ -312,7 +360,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/input-portal/*"
|
"/input-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "input-portal-no-access-token",
|
"clientId": "input-portal-no-access-token",
|
||||||
|
@ -322,7 +373,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/input-portal-no-access-token/*"
|
"/input-portal-no-access-token/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "token-min-ttl",
|
"clientId": "token-min-ttl",
|
||||||
|
@ -332,7 +386,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/token-min-ttl/*"
|
"/token-min-ttl/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "token-refresh",
|
"clientId": "token-refresh",
|
||||||
|
@ -342,7 +399,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/token-refresh/*"
|
"/token-refresh/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "third-party",
|
"clientId": "third-party",
|
||||||
|
@ -351,7 +411,10 @@
|
||||||
"/oauth-client/*",
|
"/oauth-client/*",
|
||||||
"/oauth-client-cdi/*"
|
"/oauth-client-cdi/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "basic-auth-service",
|
"clientId": "basic-auth-service",
|
||||||
|
@ -360,7 +423,10 @@
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "/basic-auth",
|
"adminUrl": "/basic-auth",
|
||||||
"baseUrl": "/basic-auth",
|
"baseUrl": "/basic-auth",
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "client-secret-jwt-secure-portal",
|
"clientId": "client-secret-jwt-secure-portal",
|
||||||
|
@ -371,7 +437,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/client-secret-jwt-secure-portal/*"
|
"/client-secret-jwt-secure-portal/*"
|
||||||
],
|
],
|
||||||
"secret": "234234-234234-234234"
|
"secret": "234234-234234-234234",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "client-secret-jwt-secure-portal-valid-alg",
|
"clientId": "client-secret-jwt-secure-portal-valid-alg",
|
||||||
|
@ -382,7 +451,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/client-secret-jwt-secure-portal-valid-alg/*"
|
"/client-secret-jwt-secure-portal-valid-alg/*"
|
||||||
],
|
],
|
||||||
"secret": "234234-234234-234234"
|
"secret": "234234-234234-234234",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,10 @@
|
||||||
"http://localhost:8180/auth/realms/master/app/*"
|
"http://localhost:8180/auth/realms/master/app/*"
|
||||||
],
|
],
|
||||||
"adminUrl": "http://localhost:8180/auth/realms/master/app/logout",
|
"adminUrl": "http://localhost:8180/auth/realms/master/app/logout",
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId" : "third-party",
|
"clientId" : "third-party",
|
||||||
|
@ -123,7 +126,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:8180/app/*"
|
"http://localhost:8180/app/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "offline-client",
|
"clientId": "offline-client",
|
||||||
|
@ -134,7 +140,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/offline-client/*"
|
"/offline-client/*"
|
||||||
],
|
],
|
||||||
"secret": "secret1"
|
"secret": "secret1",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
|
@ -66,7 +66,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/multi-tenant/tenant1/*"
|
"/multi-tenant/tenant1/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,10 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/multi-tenant/tenant2/*"
|
"/multi-tenant/tenant2/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password",
|
||||||
|
"attributes" : {
|
||||||
|
"exclude.issuer.from.auth.response": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue