21 changed files with 290 additions and 379 deletions
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
/* |
||||
* 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.authentication; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Collections; |
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken; |
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* An {@link Authentication} implementation used for the OAuth 2.0 Token Exchange Grant |
||||
* to represent an actor in a composite token (e.g. the "delegation" use case). |
||||
* |
||||
* @author Steve Riesenberg |
||||
* @since 1.3 |
||||
* @see OAuth2CompositeAuthenticationToken |
||||
*/ |
||||
public class OAuth2ActorAuthenticationToken extends AbstractAuthenticationToken implements Serializable { |
||||
|
||||
private final String name; |
||||
|
||||
public OAuth2ActorAuthenticationToken(String name) { |
||||
super(Collections.emptyList()); |
||||
Assert.hasText(name, "name cannot be empty"); |
||||
this.name = name; |
||||
} |
||||
|
||||
@Override |
||||
public Object getPrincipal() { |
||||
return this.name; |
||||
} |
||||
|
||||
@Override |
||||
public Object getCredentials() { |
||||
return null; |
||||
} |
||||
} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
/* |
||||
* 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.authentication; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
import org.springframework.security.oauth2.core.ClaimAccessor; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A {@link ClaimAccessor} used for the OAuth 2.0 Token Exchange Grant to represent an actor in a |
||||
* {@link OAuth2TokenExchangeCompositeAuthenticationToken} (e.g. the "delegation" use case). |
||||
* |
||||
* @author Steve Riesenberg |
||||
* @since 1.3 |
||||
* @see OAuth2TokenExchangeCompositeAuthenticationToken |
||||
*/ |
||||
public final class OAuth2TokenExchangeActor implements ClaimAccessor { |
||||
|
||||
private final Map<String, Object> claims; |
||||
|
||||
public OAuth2TokenExchangeActor(Map<String, Object> claims) { |
||||
Assert.notNull(claims, "claims cannot be null"); |
||||
this.claims = Collections.unmodifiableMap(claims); |
||||
} |
||||
|
||||
@Override |
||||
public Map<String, Object> getClaims() { |
||||
return this.claims; |
||||
} |
||||
|
||||
public String getIssuer() { |
||||
return getClaimAsString(OAuth2TokenClaimNames.ISS); |
||||
} |
||||
|
||||
public String getSubject() { |
||||
return getClaimAsString(OAuth2TokenClaimNames.SUB); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (!(obj instanceof OAuth2TokenExchangeActor other)) { |
||||
return false; |
||||
} |
||||
return Objects.equals(this.claims, other.claims); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(this.claims); |
||||
} |
||||
|
||||
} |
||||
25
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2CompositeAuthenticationToken.java → oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeCompositeAuthenticationToken.java
25
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2CompositeAuthenticationToken.java → oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeCompositeAuthenticationToken.java
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
/* |
||||
* 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.config.annotation.web.configurers; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
* @since 1.3 |
||||
*/ |
||||
final class DelegatingOAuth2TokenCustomizer<T extends OAuth2TokenContext> implements OAuth2TokenCustomizer<T> { |
||||
|
||||
private final List<OAuth2TokenCustomizer<T>> tokenCustomizers; |
||||
|
||||
DelegatingOAuth2TokenCustomizer(List<OAuth2TokenCustomizer<T>> tokenCustomizers) { |
||||
Assert.notEmpty(tokenCustomizers, "tokenCustomizers cannot be empty"); |
||||
this.tokenCustomizers = Collections.unmodifiableList(tokenCustomizers); |
||||
} |
||||
|
||||
@Override |
||||
public void customize(T context) { |
||||
for (OAuth2TokenCustomizer<T> tokenCustomizer : this.tokenCustomizers) { |
||||
tokenCustomizer.customize(context); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
/* |
||||
* 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.config.annotation.web.configurers; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType; |
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2CompositeAuthenticationToken; |
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeAuthenticationToken; |
||||
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext; |
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
* @since 1.3 |
||||
*/ |
||||
final class OAuth2TokenExchangeTokenCustomizers { |
||||
|
||||
private OAuth2TokenExchangeTokenCustomizers() { |
||||
} |
||||
|
||||
static OAuth2TokenCustomizer<JwtEncodingContext> jwt() { |
||||
return (context) -> context.getClaims().claims((claims) -> customize(context, claims)); |
||||
} |
||||
|
||||
static OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessToken() { |
||||
return (context) -> context.getClaims().claims((claims) -> customize(context, claims)); |
||||
} |
||||
|
||||
private static void customize(OAuth2TokenContext context, Map<String, Object> claims) { |
||||
if (!AuthorizationGrantType.TOKEN_EXCHANGE.equals(context.getAuthorizationGrantType())) { |
||||
return; |
||||
} |
||||
|
||||
if (context.getAuthorizationGrant() instanceof OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication) { |
||||
// Customize the token claims when audience is present in the request
|
||||
List<String> audience = tokenExchangeAuthentication.getAudiences(); |
||||
if (!CollectionUtils.isEmpty(audience)) { |
||||
claims.put(OAuth2TokenClaimNames.AUD, audience); |
||||
} |
||||
} |
||||
|
||||
// As per https://datatracker.ietf.org/doc/html/rfc8693#section-4.1,
|
||||
// we handle a composite principal with an actor by adding an "act"
|
||||
// claim with a "sub" claim of the actor.
|
||||
//
|
||||
// If more than one actor is present, we create a chain of delegation by
|
||||
// nesting "act" claims.
|
||||
if (context.getPrincipal() instanceof OAuth2CompositeAuthenticationToken compositeAuthenticationToken) { |
||||
Map<String, Object> currentClaims = claims; |
||||
for (Authentication actorPrincipal : compositeAuthenticationToken.getActors()) { |
||||
Map<String, Object> actClaim = new HashMap<>(); |
||||
actClaim.put("sub", actorPrincipal.getName()); |
||||
currentClaims.put("act", Collections.unmodifiableMap(actClaim)); |
||||
currentClaims = actClaim; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
10
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson2/OAuth2CompositeAuthenticationTokenMixin.java → oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson2/OAuth2TokenExchangeCompositeAuthenticationTokenMixin.java
10
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson2/OAuth2CompositeAuthenticationTokenMixin.java → oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson2/OAuth2TokenExchangeCompositeAuthenticationTokenMixin.java
Loading…
Reference in new issue