Browse Source
- Similar to custom validation in OAuth2AuthorizationCodeRequestAuthenticationProvider Closes gh-1693pull/1725/head
5 changed files with 252 additions and 7 deletions
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* Copyright 2020-2024 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.oauth2.server.authorization.oidc.authentication; |
||||
|
||||
import java.util.Map; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationContext; |
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* An {@link OAuth2AuthenticationContext} that holds an |
||||
* {@link OidcLogoutAuthenticationToken} and additional information and is used when |
||||
* validating the OpenID Connect RP-Initiated Logout Request parameters. |
||||
* |
||||
* @author Daniel Garnier-Moiroux |
||||
* @since 1.4 |
||||
* @see OAuth2AuthenticationContext |
||||
* @see OidcLogoutAuthenticationToken |
||||
* @see OidcLogoutAuthenticationProvider#setAuthenticationValidator(Consumer) |
||||
*/ |
||||
public final class OidcLogoutAuthenticationContext implements OAuth2AuthenticationContext { |
||||
|
||||
private final Map<Object, Object> context; |
||||
|
||||
private OidcLogoutAuthenticationContext(Map<Object, Object> context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Nullable |
||||
@Override |
||||
public <V> V get(Object key) { |
||||
return hasKey(key) ? (V) this.context.get(key) : null; |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasKey(Object key) { |
||||
Assert.notNull(key, "key cannot be null"); |
||||
return this.context.containsKey(key); |
||||
} |
||||
|
||||
/** |
||||
* Returns the {@link RegisteredClient registered client}. |
||||
* @return the {@link RegisteredClient} |
||||
*/ |
||||
public RegisteredClient getRegisteredClient() { |
||||
return get(RegisteredClient.class); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new {@link Builder} with the provided |
||||
* {@link OidcLogoutAuthenticationToken}. |
||||
* @param authentication the {@link OidcLogoutAuthenticationToken} |
||||
* @return the {@link Builder} |
||||
*/ |
||||
public static Builder with(OidcLogoutAuthenticationToken authentication) { |
||||
return new Builder(authentication); |
||||
} |
||||
|
||||
/** |
||||
* A builder for {@link OidcLogoutAuthenticationContext}. |
||||
*/ |
||||
public static final class Builder extends AbstractBuilder<OidcLogoutAuthenticationContext, Builder> { |
||||
|
||||
private Builder(Authentication authentication) { |
||||
super(authentication); |
||||
} |
||||
|
||||
/** |
||||
* Sets the {@link RegisteredClient registered client}. |
||||
* @param registeredClient the {@link RegisteredClient} |
||||
* @return the {@link Builder} for further configuration |
||||
*/ |
||||
public Builder registeredClient(RegisteredClient registeredClient) { |
||||
return put(RegisteredClient.class, registeredClient); |
||||
} |
||||
|
||||
/** |
||||
* Builds a new {@link OidcLogoutAuthenticationContext}. |
||||
* @return the {@link OidcLogoutAuthenticationContext} |
||||
*/ |
||||
@Override |
||||
public OidcLogoutAuthenticationContext build() { |
||||
return new OidcLogoutAuthenticationContext(getContext()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
/* |
||||
* Copyright 2020-2024 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.oauth2.server.authorization.oidc.authentication; |
||||
|
||||
import java.util.function.Consumer; |
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |
||||
import org.springframework.security.oauth2.core.OAuth2Error; |
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; |
||||
import org.springframework.security.oauth2.core.oidc.OidcIdToken; |
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* A {@code Consumer} providing access to the {@link OidcLogoutAuthenticationContext} |
||||
* containing an {@link OidcLogoutAuthenticationToken} and is the default |
||||
* {@link OidcLogoutAuthenticationProvider#setAuthenticationValidator(Consumer) |
||||
* authentication validator} used for validating specific OpenID Connect RP-Initiated |
||||
* Logout parameters used in the Authorization Code Grant. |
||||
* |
||||
* <p> |
||||
* The default implementation first validates {@link OidcIdToken#getAudience()}, and then |
||||
* {@link OidcLogoutAuthenticationToken#getPostLogoutRedirectUri()}. If validation fails, |
||||
* an {@link OAuth2AuthenticationException} is thrown. |
||||
* |
||||
* @author Daniel Garnier-Moiroux |
||||
* @since 1.4 |
||||
* @see OidcLogoutAuthenticationContext |
||||
* @see OidcLogoutAuthenticationToken |
||||
* @see OidcLogoutAuthenticationProvider#setAuthenticationValidator(Consumer) |
||||
*/ |
||||
public final class OidcLogoutAuthenticationValidator implements Consumer<OidcLogoutAuthenticationContext> { |
||||
|
||||
/** |
||||
* The default validator for |
||||
* {@link OidcLogoutAuthenticationToken#getPostLogoutRedirectUri()}. |
||||
*/ |
||||
public static final Consumer<OidcLogoutAuthenticationContext> DEFAULT_POST_LOGOUT_REDIRECT_URI_VALIDATOR = OidcLogoutAuthenticationValidator::validatePostLogoutRedirectUri; |
||||
|
||||
private final Consumer<OidcLogoutAuthenticationContext> authenticationValidator = DEFAULT_POST_LOGOUT_REDIRECT_URI_VALIDATOR; |
||||
|
||||
@Override |
||||
public void accept(OidcLogoutAuthenticationContext authenticationContext) { |
||||
this.authenticationValidator.accept(authenticationContext); |
||||
} |
||||
|
||||
private static void validatePostLogoutRedirectUri(OidcLogoutAuthenticationContext authenticationContext) { |
||||
OidcLogoutAuthenticationToken oidcLogoutAuthentication = authenticationContext.getAuthentication(); |
||||
RegisteredClient registeredClient = authenticationContext.getRegisteredClient(); |
||||
if (StringUtils.hasText(oidcLogoutAuthentication.getPostLogoutRedirectUri()) |
||||
&& !registeredClient.getPostLogoutRedirectUris() |
||||
.contains(oidcLogoutAuthentication.getPostLogoutRedirectUri())) { |
||||
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, |
||||
"OpenID Connect 1.0 Logout Request Parameter: post_logout_redirect_uri", |
||||
"https://openid.net/specs/openid-connect-rpinitiated-1_0.html#ValidationAndErrorHandling"); |
||||
throw new OAuth2AuthenticationException(error); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue