forked from Azure/azure-sdk-for-java
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE REQ] Make it easier to debug aad-starter (Azure#22289)
- Loading branch information
Moary Chen
authored
Jun 30, 2021
1 parent
ff2320a
commit c848f61
Showing
22 changed files
with
352 additions
and
374 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
...ure-spring-boot/src/main/java/com/azure/spring/aad/AADJwtGrantedAuthoritiesConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
package com.azure.spring.aad; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.core.convert.converter.Converter; | ||
import org.springframework.security.core.GrantedAuthority; | ||
import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||
import org.springframework.security.oauth2.jwt.Jwt; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.stream.Stream; | ||
|
||
/** | ||
* Extracts the {@link GrantedAuthority}s from scope attributes typically found in a {@link Jwt}. | ||
*/ | ||
public class AADJwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> { | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(AADJwtGrantedAuthoritiesConverter.class); | ||
public static final Map<String, String> DEFAULT_CLAIM_TO_AUTHORITY_PREFIX_MAP; | ||
public static final String DEFAULT_AUTHORITY_CLAIM_NAME = "scp"; | ||
public static final String DEFAULT_AUTHORITY_PREFIX = "SCOPE_"; | ||
|
||
static { | ||
Map<String, String> claimAuthorityMap = new HashMap<>(); | ||
claimAuthorityMap.put(DEFAULT_AUTHORITY_CLAIM_NAME, DEFAULT_AUTHORITY_PREFIX); | ||
claimAuthorityMap.put("roles", "APPROLE_"); | ||
DEFAULT_CLAIM_TO_AUTHORITY_PREFIX_MAP = Collections.unmodifiableMap(claimAuthorityMap); | ||
} | ||
|
||
private final Map<String, String> claimToAuthorityPrefixMap; | ||
|
||
public AADJwtGrantedAuthoritiesConverter() { | ||
claimToAuthorityPrefixMap = DEFAULT_CLAIM_TO_AUTHORITY_PREFIX_MAP; | ||
} | ||
|
||
public AADJwtGrantedAuthoritiesConverter(Map<String, String> claimToAuthorityPrefixMap) { | ||
this.claimToAuthorityPrefixMap = claimToAuthorityPrefixMap; | ||
} | ||
|
||
@Override | ||
public Collection<GrantedAuthority> convert(Jwt jwt) { | ||
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>(); | ||
claimToAuthorityPrefixMap.forEach((authoritiesClaimName, authorityPrefix) -> { | ||
Optional.of(authoritiesClaimName) | ||
.map(jwt::getClaim) | ||
.map(this::getClaimValueAsCollection) | ||
.map(Collection::stream) | ||
.orElseGet(Stream::empty) | ||
.map(authority -> authorityPrefix + authority) | ||
.map(SimpleGrantedAuthority::new) | ||
.forEach(grantedAuthorities::add); | ||
|
||
}); | ||
LOGGER.debug("User {}'s authorities created from jwt token: {}.", jwt.getSubject(), grantedAuthorities); | ||
return grantedAuthorities; | ||
} | ||
|
||
private Collection<?> getClaimValueAsCollection(Object claimValue) { | ||
if (claimValue instanceof String) { | ||
return Arrays.asList(((String) claimValue).split(" ")); | ||
} else if (claimValue instanceof Collection) { | ||
return (Collection<?>) claimValue; | ||
} else { | ||
return Collections.emptyList(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
...oot/src/main/java/com/azure/spring/aad/AbstractJwtBearerTokenAuthenticationConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
package com.azure.spring.aad; | ||
|
||
import org.springframework.core.convert.converter.Converter; | ||
import org.springframework.security.authentication.AbstractAuthenticationToken; | ||
import org.springframework.security.core.GrantedAuthority; | ||
import org.springframework.security.oauth2.core.OAuth2AccessToken; | ||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; | ||
import org.springframework.security.oauth2.jwt.Jwt; | ||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; | ||
import org.springframework.util.Assert; | ||
|
||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* An abstract {@link Converter} that takes a {@link Jwt} and converts it into a {@link BearerTokenAuthentication}. | ||
*/ | ||
public abstract class AbstractJwtBearerTokenAuthenticationConverter implements Converter<Jwt, | ||
AbstractAuthenticationToken> { | ||
|
||
public static final String DEFAULT_PRINCIPAL_CLAIM_NAME = "sub"; | ||
protected Converter<Jwt, Collection<GrantedAuthority>> converter; | ||
protected String principalClaimName; | ||
|
||
public AbstractJwtBearerTokenAuthenticationConverter(String principalClaimName, | ||
Map<String, String> claimToAuthorityPrefixMap) { | ||
Assert.notNull(claimToAuthorityPrefixMap, "claimToAuthorityPrefixMap cannot be null"); | ||
this.principalClaimName = principalClaimName; | ||
this.converter = new AADJwtGrantedAuthoritiesConverter(claimToAuthorityPrefixMap); | ||
} | ||
|
||
@Override | ||
public AbstractAuthenticationToken convert(Jwt jwt) { | ||
OAuth2AccessToken accessToken = new OAuth2AccessToken( | ||
OAuth2AccessToken.TokenType.BEARER, jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt()); | ||
Collection<GrantedAuthority> authorities = converter.convert(jwt); | ||
OAuth2AuthenticatedPrincipal principal = getAuthenticatedPrincipal( | ||
jwt.getHeaders(), jwt.getClaims(), authorities, jwt.getTokenValue()); | ||
return new BearerTokenAuthentication(principal, accessToken, authorities); | ||
} | ||
|
||
protected static Map<String, String> buildClaimToAuthorityPrefixMap(String authoritiesClaimName, | ||
String authorityPrefix) { | ||
Assert.notNull(authoritiesClaimName, "authoritiesClaimName cannot be null"); | ||
Assert.notNull(authorityPrefix, "authorityPrefix cannot be null"); | ||
Map<String, String> claimToAuthorityPrefixMap = new HashMap<>(); | ||
claimToAuthorityPrefixMap.put(authoritiesClaimName, authorityPrefix); | ||
return claimToAuthorityPrefixMap; | ||
} | ||
|
||
/** | ||
* Construct an instance of OAuth2AuthenticatedPrincipal interface. | ||
* | ||
* @param headers Jwt header map | ||
* @param claims Jwt claims map | ||
* @param authorities Jwt authorities collection | ||
* @param tokenValue Jwt token value | ||
* @return an OAuth2AuthenticatedPrincipal instance. | ||
*/ | ||
protected abstract OAuth2AuthenticatedPrincipal getAuthenticatedPrincipal(Map<String, Object> headers, | ||
Map<String, Object> claims, | ||
Collection<GrantedAuthority> authorities, | ||
String tokenValue); | ||
|
||
public void setConverter( | ||
Converter<Jwt, Collection<GrantedAuthority>> converter) { | ||
this.converter = converter; | ||
} | ||
|
||
public void setPrincipalClaimName(String principalClaimName) { | ||
Assert.hasText(principalClaimName, "principalClaimName cannot be empty"); | ||
this.principalClaimName = principalClaimName; | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...ationCodeGrantRequestEntityConverter.java → ...ationCodeGrantRequestEntityConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.