microsoft / azure-spring-boot

Spring Boot Starters for Azure services
MIT License
376 stars 460 forks source link

invalid issuer in UserPrincipalManager #642

Closed jtc198322 closed 5 years ago

jtc198322 commented 5 years ago

JWTClaimsSet checks for issuer that is not equal to my token, how can I override this or resolve with configuration.

Environment

Summary

Issuer from azure ad is https://login.microsoftonline.com/uuid/v2.0 Code throws BadJWTException because the issuer doesn't contain "https://sts.windows.net/" or "https://sts.chinacloudapi.cn/".

Reproduce steps

Add spring boot starter to my zuul project, then configured aad app, added properties and security config below.

`@Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AADAuthenticationFilter aadAuthFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {

    // Disable CSRF (cross site request forgery)
    http.cors().and().csrf().disable();

    // No session will be created or used by spring security
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    // Entry points
    http.authorizeRequests()
            .antMatchers("/signin").permitAll()
            // Disallow everything else..
            .anyRequest().authenticated();

    // If a user try to access a resource without having enough permissions
    http.exceptionHandling().accessDeniedPage("/login");
    http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);

    // Apply JWT
   // http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));

    // Optional, if you want to test the API from a browser
    // http.httpBasic();
}

@Override
public void configure(WebSecurity web) throws Exception {
    // Allow eureka client to be accessed without authentication
    web.ignoring().antMatchers("/*/")//
            .antMatchers("/eureka/**")//
            .antMatchers(HttpMethod.OPTIONS, "/**"); // Request type options should be allowed.
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
}

@Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
    return authenticationManager();
}

} `

Expected Results

Validate token from issuer https://login.microsoftonline.com/uuid/v2.0

Actual Results

BadJWTException("Invalid token issuer")

`

 private ConfigurableJWTProcessor<SecurityContext> getAadJwtTokenValidator(JWSAlgorithm jwsAlgorithm) {
        final ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
    final JWSKeySelector<SecurityContext> keySelector =
            new JWSVerificationKeySelector<>(jwsAlgorithm, keySource);
    jwtProcessor.setJWSKeySelector(keySelector);

    jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<SecurityContext>() {
        @Override
        public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException {
            super.verify(claimsSet, ctx);
            final String issuer = claimsSet.getIssuer();
            if (issuer == null || !issuer.contains("https://sts.windows.net/")
                    && !issuer.contains("https://sts.chinacloudapi.cn/")) {
                throw new BadJWTException("Invalid token issuer");
            }
        }
    });
    return jwtProcessor;
}

`

Incarnation-p-lee commented 5 years ago

@jtc198322 Thanks for issue this. For double check, you only leverage AADAuthenticationFilter for your security configuration, right ?

The filter only take care of Auhorization header and validate it from below configuration https://github.com/Microsoft/azure-spring-boot/blob/0caebdeaf694a69619eb07d39f1ca0ca3c81cc2f/azure-spring-boot/src/main/resources/serviceEndpoints.properties#L1-L8

You may need to provide more configuration about you code, so we can tell where is wired.

jtc198322 commented 5 years ago

I didn't have most of these in place but I added a few. Same results

azure: 
  activedirectory:
    clientId:  ***********************************
    clientSecret: *******************************
    activeDirectoryGroups: group1,group2
  service:
    endpoints:
      global:
        aad-signin-uri: https://login.microsoftonline.com/
        aadGraphApiUri: https://graph.windows.net/****************************
Incarnation-p-lee commented 5 years ago

@jtc198322 In fact you may not have necessary to configure that, use default value from serviceEndpoints.properties is good enough

jtc198322 commented 5 years ago

Most examples only indicate these...

`azure: 
  activedirectory:
    clientId:  ***********************************
    clientSecret: *******************************
    activeDirectoryGroups: group1,group2`

Looks like the only way to avoid this code in the filter is not to get into the below, should I already have any of these to make this false?

    ` if (principal == null || graphApiToken == null || graphApiToken.isEmpty()) {
                    principal = principalManager.buildUserPrincipal(idToken);

                    final String tenantId = principal.getClaim().toString();
                    graphApiToken = client.acquireTokenForGraphApi(idToken, tenantId).getAccessToken();

                    principal.setUserGroups(client.getGroups(graphApiToken));

                    request.getSession().setAttribute(CURRENT_USER_PRINCIPAL, principal);
                    request.getSession().setAttribute(CURRENT_USER_PRINCIPAL_GRAPHAPI_TOKEN, graphApiToken);
                }`
jtc198322 commented 5 years ago

Would it be possible to make the hard-corded strings of the issuer dynamic supported by properties? For a single tenant...

@Override public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException { super.verify(claimsSet, ctx); final String issuer = claimsSet.getIssuer(); if (issuer == null || !issuer.contains("https://sts.windows.net/") && !issuer.contains("https://sts.chinacloudapi.cn/")) { throw new BadJWTException("Invalid token issuer"); } } });

Incarnation-p-lee commented 5 years ago

@jtc198322 I am sorry it seems I cannot get your point for this issue. For aad, the service-endpoint is something like fixed value, and it should works well. Are you try to customize this endpoint with aad ? I am not sure if it is possible or not. Please correct me if something misunderstanding.

jtc198322 commented 5 years ago

Basically my issuer from Azure AD is not "https://sts.windows.net/" or "https://sts.chinacloudapi.cn/"

it is from https://login.microsoftonline.com/{uuid}/v2.0

and the jwt verification fails. This OOTB from Azure, I didn't customize it

TimGundmann commented 5 years ago

I have the same issue. I think the error occur if the setup is single tenant.

afrancoc2000 commented 5 years ago

I think the problem is giving an azure AD v2 token to a azure AD v1 implementation.

shrabdut123 commented 5 years ago

Facing similar issue with single tenant application, is there any solution to this issue?

berndgoetz commented 5 years ago

I think I'm facing the same issue here. I'm using the AAD Spring Boot starter with Spring Boot 2.1.4 and I receive version 1.0 tokens. The access token is not a JWT, the id token is and it includes the attribute "ver": "1.0" and "iss": "https://sts.windows.net/our-tenant-id/", whereas it should be "iss": "https://login.microsoftonline.com/our-tenant-id/v2.0".

Here's my application.yml:

spring:
  application:
    name: app-name
  security:
    oauth2:
      client:
        registration:
          azure:
            client-id: my-client-id
            client-secret: my-client-secret
...
azure:
  activedirectory:
    tenant-id: our-tenant-id
    active-directory-groups: group1, group2, admin
...

How can I configure AAD in my app to generate ver 2.0 tokens?

If somebody tells me that this is a different issue, I'll create a new issue.

afrancoc2000 commented 5 years ago

@berndgoetz if you are having this issue you are already generating v2.0 tokens, the springboot implementation verifies the tokens using the adal for java library that validates v1.0 tokens and checks the issuer whitout incluind the "https://login.microsoftonline.com" issuer. You can do your own implementation using msal for java to validate v2.0 tokens or change the tokens you are sending to v1.0. I have been working in the msal implementation but didn't finished it because of a problem with the obo flow here is a link to my issue: problem with obo flow

javolek commented 5 years ago

Wouldn't it be easier to get the correct issuer from https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration or https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration for v2.0 respectively, instead of hardcoding them?

sandeepjain98 commented 5 years ago

Hi all, Even I am facing the same issue. any workaround so far. I am generating a token from msal in the web app and trying to authenticate it in Java(web api) using this lib "azure-active-directory-spring-boot-starter" . the problem is the token generated in msal having "https://login.microsoftonline.com" as issuer but the principal class checks for "https://sts.windows.net"

superrdean commented 5 years ago

now the issuer(https://login.microsoftonline.com) has been added to the verifier. And the change has been merged to the master. You can try it by using the latest SNAPSHOT or 2.1.7 dependency.

sasmitanair commented 5 years ago

I am facing the same issuer problem. I downloaded 2.1.7 version

com.microsoft.azure azure-spring-boot 2.1.7

But the code within 2.1.7 does not reflect "https://login.microsoftonline.com"

I can see the fix is available at https://github.com/microsoft/azure-spring-boot/blob/master/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/UserPrincipalManager.java

But the 2.1.7 jars downloaded by maven still contains the old code.

To double check I downloaded source code from https://github.com/microsoft/azure-spring-boot/releases/tag/2.1.7 and yes it still contains the old version of the code (i.e. the fix to include "https://login.microsoftonline.com" within token verify is missing)

Can you please confirm which version should be downloaded to get the updates?

saragluna commented 5 years ago

@sasmitanair Thanks for pointing out this. You're right about the 2.1.7 release, the change's not been released with it. So perhaps you could try it with our daily built snapshot.