Allow empty token endpoint for implicit flow (#45038)
When using the implicit flow in OpenID Connect, the op.token_endpoint_url should not be mandatory as there is no need to contact the token endpoint of the OP.
This commit is contained in:
parent
ddcc38cf1c
commit
99ddb8b3d8
|
@ -23,9 +23,10 @@ public class OpenIdConnectProviderConfiguration {
|
||||||
private final String jwkSetPath;
|
private final String jwkSetPath;
|
||||||
|
|
||||||
public OpenIdConnectProviderConfiguration(Issuer issuer, String jwkSetPath, URI authorizationEndpoint,
|
public OpenIdConnectProviderConfiguration(Issuer issuer, String jwkSetPath, URI authorizationEndpoint,
|
||||||
URI tokenEndpoint, @Nullable URI userinfoEndpoint, @Nullable URI endsessionEndpoint) {
|
@Nullable URI tokenEndpoint, @Nullable URI userinfoEndpoint,
|
||||||
|
@Nullable URI endsessionEndpoint) {
|
||||||
this.authorizationEndpoint = Objects.requireNonNull(authorizationEndpoint, "Authorization Endpoint must be provided");
|
this.authorizationEndpoint = Objects.requireNonNull(authorizationEndpoint, "Authorization Endpoint must be provided");
|
||||||
this.tokenEndpoint = Objects.requireNonNull(tokenEndpoint, "Token Endpoint must be provided");
|
this.tokenEndpoint = tokenEndpoint;
|
||||||
this.userinfoEndpoint = userinfoEndpoint;
|
this.userinfoEndpoint = userinfoEndpoint;
|
||||||
this.endsessionEndpoint = endsessionEndpoint;
|
this.endsessionEndpoint = endsessionEndpoint;
|
||||||
this.issuer = Objects.requireNonNull(issuer, "OP Issuer must be provided");
|
this.issuer = Objects.requireNonNull(issuer, "OP Issuer must be provided");
|
||||||
|
|
|
@ -281,25 +281,31 @@ public class OpenIdConnectRealm extends Realm implements Releasable {
|
||||||
// This should never happen as it's already validated in the settings
|
// This should never happen as it's already validated in the settings
|
||||||
throw new SettingsException("Invalid URI: " + OP_AUTHORIZATION_ENDPOINT.getKey(), e);
|
throw new SettingsException("Invalid URI: " + OP_AUTHORIZATION_ENDPOINT.getKey(), e);
|
||||||
}
|
}
|
||||||
|
String responseType = require(config, RP_RESPONSE_TYPE);
|
||||||
|
String tokenEndpointString = config.getSetting(OP_TOKEN_ENDPOINT);
|
||||||
|
if (responseType.equals("code") && tokenEndpointString.isEmpty()) {
|
||||||
|
throw new SettingsException("The configuration setting [" + OP_TOKEN_ENDPOINT.getConcreteSettingForNamespace(name()).getKey()
|
||||||
|
+ "] is required when [" + RP_RESPONSE_TYPE.getConcreteSettingForNamespace(name()).getKey() + "] is set to \"code\"");
|
||||||
|
}
|
||||||
URI tokenEndpoint;
|
URI tokenEndpoint;
|
||||||
try {
|
try {
|
||||||
tokenEndpoint = new URI(require(config, OP_TOKEN_ENDPOINT));
|
tokenEndpoint = tokenEndpointString.isEmpty() ? null : new URI(tokenEndpointString);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
// This should never happen as it's already validated in the settings
|
// This should never happen as it's already validated in the settings
|
||||||
throw new SettingsException("Invalid URL: " + OP_TOKEN_ENDPOINT.getKey(), e);
|
throw new SettingsException("Invalid URL: " + OP_TOKEN_ENDPOINT.getKey(), e);
|
||||||
}
|
}
|
||||||
URI userinfoEndpoint;
|
URI userinfoEndpoint;
|
||||||
try {
|
try {
|
||||||
userinfoEndpoint = (config.getSetting(OP_USERINFO_ENDPOINT, () -> null) == null) ? null :
|
userinfoEndpoint = (config.getSetting(OP_USERINFO_ENDPOINT).isEmpty()) ? null :
|
||||||
new URI(config.getSetting(OP_USERINFO_ENDPOINT, () -> null));
|
new URI(config.getSetting(OP_USERINFO_ENDPOINT));
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
// This should never happen as it's already validated in the settings
|
// This should never happen as it's already validated in the settings
|
||||||
throw new SettingsException("Invalid URI: " + OP_USERINFO_ENDPOINT.getKey(), e);
|
throw new SettingsException("Invalid URI: " + OP_USERINFO_ENDPOINT.getKey(), e);
|
||||||
}
|
}
|
||||||
URI endsessionEndpoint;
|
URI endsessionEndpoint;
|
||||||
try {
|
try {
|
||||||
endsessionEndpoint = (config.getSetting(OP_ENDSESSION_ENDPOINT, () -> null) == null) ? null :
|
endsessionEndpoint = (config.getSetting(OP_ENDSESSION_ENDPOINT).isEmpty()) ? null :
|
||||||
new URI(config.getSetting(OP_ENDSESSION_ENDPOINT, () -> null));
|
new URI(config.getSetting(OP_ENDSESSION_ENDPOINT));
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
// This should never happen as it's already validated in the settings
|
// This should never happen as it's already validated in the settings
|
||||||
throw new SettingsException("Invalid URI: " + OP_ENDSESSION_ENDPOINT.getKey(), e);
|
throw new SettingsException("Invalid URI: " + OP_ENDSESSION_ENDPOINT.getKey(), e);
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
|
||||||
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT)));
|
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMissingTokenEndpointThrowsError() {
|
public void testMissingTokenEndpointThrowsErrorInCodeFlow() {
|
||||||
final Settings.Builder settingsBuilder = Settings.builder()
|
final Settings.Builder settingsBuilder = Settings.builder()
|
||||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
||||||
|
@ -103,6 +103,22 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
|
||||||
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT)));
|
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMissingTokenEndpointIsAllowedInImplicitFlow() {
|
||||||
|
final Settings.Builder settingsBuilder = Settings.builder()
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_JWKSET_PATH), "https://op.example.com/jwks.json")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
|
||||||
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "id_token token");
|
||||||
|
settingsBuilder.setSecureSettings(getSecureSettings());
|
||||||
|
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
|
||||||
|
assertNotNull(realm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testInvalidTokenEndpointThrowsError() {
|
public void testInvalidTokenEndpointThrowsError() {
|
||||||
final Settings.Builder settingsBuilder = Settings.builder()
|
final Settings.Builder settingsBuilder = Settings.builder()
|
||||||
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
|
||||||
|
|
Loading…
Reference in New Issue