Reputation: 562
I am using Azure AD to carry out the users authentication of a spring boot app. I need to generate the token for some reasons from spring boot code and return it. So far this is what I have achieve.
1 Azure Ad config.
I have config a app within azure Ad and I have register One user and one group.
within the app i also have create a secret
Now in my spring boot app i have added the JWT filter and some config (I am not going to explain the full config because it will take a while)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Profile("AzureAdSecurized")
public class AzureSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationExceptionHandler restAuthenticationExceptionHandler;
@Autowired
private AADAppRoleStatelessAuthenticationFilter aadAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
http.headers().frameOptions().disable();
http.addFilterAfter(aadAuthenticationFilter, UsernamePasswordAuthenticationFilter.class );
http.addFilterBefore( new CorsFilter(), ChannelProcessingFilter.class );
http.exceptionHandling().authenticationEntryPoint( restAuthenticationExceptionHandler );
//Configuracion Endpoints
http.authorizeRequests().antMatchers( "/auth/login**" ).permitAll()
.antMatchers( "/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**" ).permitAll()
.antMatchers( "/actuator/**" ).permitAll().anyRequest().authenticated();
}
I also have added the following properties:
azure:
activedirectory:
tenant-id: 7XXXXX
client-id: 5XXXXX
session-stateless: true
spring:
security:
oauth2:
client:
registration:
azure:
client-id: 5XXX
client-secret: dXXXX
if I go to the following URL of microsoft: https://login.microsoftonline.com//oauth2/authorize?client_id=&response_type=id_token&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&nonce=7362CAEA-9CA5–4B43–9BA3–34D7C303EBA7
I get a perfect Token in a redirection like: http://localhost:8080/login#id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWp
with this token I perfectly pass the aadAuthenticationFilter of spring boot security.
The point is that i have to generate this token from the app.
In my spring boot app I have algo add: I have follow a tutorial but i dont no remeber url
@RestController
@RequestMapping(LoginPaths.AUTH)
@Profile("AzureAdSecurized")
public class AADLoginController {
private static final Logger LOG = LoggerFactory.getLogger( AADLoginController.class );
@RequestMapping(value = LoginPaths.LOGIN, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String generateTokenAzureAD() throws MalformedURLException, ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool( 1 );
AuthenticationContext context = new AuthenticationContext(
"https://login.microsoftonline.com/<My-tenant>/oauth2/v2.0/authorize", false,
service );
Future<AuthenticationResult> future = context
.acquireToken( "https://graph.microsoft.com",
"<app-id>", "<username>",
"<pass>", null );
AuthenticationResult result = future.get();
LOG.info( "Access Token - " + result.getAccessToken() );
LOG.info( "Refresh Token - " + result.getRefreshToken() );
LOG.info( "ID Token - " + result.getIdToken() );
return "Bearer " + result.getAccessToken();
}
}
by passing username and password with classes of library "com.microsoft.aad.adal4j" I am trying to generate I token.
The token I receive is the following:
As you can see the token has information related with my user and so on and it seems to be correct, but the signature is not valid and if a send a request to my app with such token. obviously it gives me and error for invalid signature.
What I am doing wrong?
Thank you very much
Upvotes: 1
Views: 1998
Reputation: 562
I am usisng the dependency instead:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
</dependency>
And generating tokens this way:
public TokenDTO generateTokenAzureAD(CredentialsDTO credentialsDTO) {
LoginValidator.validateLoginRequest( credentialsDTO );
PublicClientApplication app;
String AUTHORITY = authorityUrl + addTenantId;
try {
app = PublicClientApplication.builder( addAppId ).authority( AUTHORITY ).build();
} catch (MalformedURLException e) {
throw new MyException( ErrorCodes.ERROR_ADD_AUTHORITY_URL_NOT_VALID );
}
Set<String> scopes = Collections.singleton( addAppId + addAppScope );
UserNamePasswordParameters parameters = UserNamePasswordParameters
.builder( scopes, credentialsDTO.getUsername(), credentialsDTO.getPassword().toCharArray() ).build();
Future<IAuthenticationResult> result = app.acquireToken( parameters );
IAuthenticationResult auth;
try {
auth = result.get();
} catch (InterruptedException | ExecutionException e) {
throw new MyException( ErrorCodes.ERROR_ADD_AUTHORITY_URL_NOT_VALID );
}
return TokenUtils.fromAddAuthToTokenDTO( auth );
}
Where
authorityUrl = https://login.microsoftonline.com/
addTenantId = azureID tenant
addAppId = azureID app ID
addAppScope = /User.Read
for scopes yo can create a new one in "Expose API" option of azure AD app menu
Thanks also to @TonyJu
Upvotes: 1
Reputation: 15619
Your token is correct. It is just a specific token for graph api. You will see a nonce
in Jwt.Header. This means you need special processing. Normal processing will fail.
Update:
Access tokens are opaque blobs of text that are for the resource only. If you're a client getting a token for Graph, assume that it's an encrypted string that you should never look at - sometimes it will be. We use a special token format for Graph that they know how to validate - you shouldn't be looking at access tokens if they're not for you.
Reference:
Upvotes: 1