Azure-Samples/azure-spring-boot-samples

Unable to validate token on lambda console

abdulrais opened this issue · 3 comments

Hi Team,

I am using spring security OAuth2 with Azure AD. When I am testing APIs on local server everything seems fine and getting expected result with token Authenticated or proper response in case of invalid token but when I am running same thing on AWS lambda i am getting 401. I don't know what I am missing. Attaching logs from localhost and aws server for your reference:

Logs from localhost:

2023-02-22 14:11:53.105  INFO 14964 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-02-22 14:11:53.105  INFO 14964 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.62]
2023-02-22 14:11:53.312  INFO 14964 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-02-22 14:11:53.312  INFO 14964 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2061 ms
2023-02-22 14:11:53.417 DEBUG 14964 --- [           main] .PrePostAnnotationSecurityMetadataSource : @org.springframework.security.access.prepost.PreAuthorize("hasAuthority(\'APPROLE_ADMIN\')") 
2023-02-22 14:11:53.420 DEBUG 14964 --- [           main] m.DelegatingMethodSecurityMetadataSource :  with attributes [[authorize: 'hasAuthority('APPROLE_ADMIN')', filter: 'null', filterTarget: 'null']]
2023-02-22 14:11:53.608 DEBUG 14964 --- [           main] swordEncoderAuthenticationManagerBuilder : No authenticationProviders and no parentAuthenticationManager defined. Returning null.
inside OAuth2
getting outside OAuth2
2023-02-22 14:11:53.821 DEBUG 14964 --- [           main] edFilterInvocationSecurityMetadataSource : Adding web access control expression [authenticated] for any request
2023-02-22 14:11:53.829  INFO 14964 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5af5d76f, org.springframework.security.web.context.SecurityContextPersistenceFilter@61a2aeb7, org.springframework.security.web.header.HeaderWriterFilter@6042d663, org.springframework.security.web.csrf.CsrfFilter@abad89c, org.springframework.security.web.authentication.logout.LogoutFilter@1775c4e7, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@23ad71bf, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5f8d9767, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1980a3f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3a8cea24, org.springframework.security.web.session.SessionManagementFilter@7a682d35, org.springframework.security.web.access.ExceptionTranslationFilter@61ff6a49, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@6fe595dc]
2023-02-22 14:11:54.471  INFO 14964 --- [           main] c.a.c.i.jackson.JacksonVersion           : Package versions: jackson-annotations=2.13.2, jackson-core=2.13.2, jackson-databind=2.13.3, jackson-dataformat-xml=2.13.2, jackson-datatype-jsr310=2.13.2, azure-core=1.26.0, Troubleshooting version conflicts: https://aka.ms/azsdk/java/dependency/troubleshoot
2023-02-22 14:11:54.611  INFO 14964 --- [           main] AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.identity.DefaultAzureCredentialBuilder.
2023-02-22 14:11:54.901  INFO 14964 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-02-22 14:11:54.923  INFO 14964 --- [           main]    : Started in 4.4 seconds (JVM running for 5.241)
2023-02-22 14:18:26.550  INFO 14964 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-22 14:18:26.551  INFO 14964 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-22 14:18:26.553  INFO 14964 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
2023-02-22 14:18:26.576 DEBUG 14964 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /
2023-02-22 14:18:26.585 DEBUG 14964 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2023-02-22 14:18:27.540 DEBUG 14964 --- [nio-8080-exec-2] o.s.s.o.s.r.a.JwtAuthenticationProvider  : Authenticated token
2023-02-22 14:18:27.541 DEBUG 14964 --- [nio-8080-exec-2] .o.s.r.w.BearerTokenAuthenticationFilter : Set SecurityContextHolder to JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@4ff204a1, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[SCOPE_access_as_user]]
2023-02-22 14:18:27.556 DEBUG 14964 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorized filter invocation [GET /] with attributes [authenticated]
2023-02-22 14:18:27.557 DEBUG 14964 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Secured GET /
org.springframework.security.oauth2.jwt.Jwt@4ff204a1
2023-02-22 14:18:27.699 DEBUG 14964 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request

Logs from AWS:

2023-02-22 11:18:48.933 DEBUG 8 --- [           main] edFilterInvocationSecurityMetadataSource : Adding web access control expression [authenticated] for any request

2023-02-22 11:18:49.055  INFO 8 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@57ac5227, org.springframework.security.web.context.SecurityContextPersistenceFilter@bf1ec20, org.springframework.security.web.header.HeaderWriterFilter@38f116f6, org.springframework.security.web.csrf.CsrfFilter@736d6a5c, org.springframework.security.web.authentication.logout.LogoutFilter@7fe7c640, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@4795ded0, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@b70da4c, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@435fb7b5, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4ba302e0, org.springframework.security.web.session.SessionManagementFilter@c5ee75e, org.springframework.security.web.access.ExceptionTranslationFilter@424fd310, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@43aaf813]

2023-02-22 11:18:57.413  INFO 8 --- [           main] s.c.a.i.c.AzureSpringBootVersionVerifier : Cannot check Boot version from manifest

2023-02-22 11:18:57.433  INFO 8 --- [           main] s.c.a.i.c.AzureSpringBootVersionVerifier : Cannot check Boot version from manifest

2023-02-22 11:18:58.234  INFO 8 --- [           main] c.a.c.i.jackson.JacksonVersion           : Package versions: jackson-annotations=unknown, jackson-core=unknown, jackson-databind=unknown, jackson-dataformat-xml=unknown, jackson-datatype-jsr310=unknown, azure-core=1.26.0, Troubleshooting version conflicts: https://aka.ms/azsdk/java/dependency/troubleshoot

2023-02-22 11:18:59.476  INFO 8 --- [           main] AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.identity.DefaultAzureCredentialBuilder.

2023-02-22 11:19:02.634  INFO 8 --- [           main] lambdainternal.AWSLambda                 : Started AWSLambda in 39.898 seconds (JVM running for 45.01)

2023-02-22 11:19:02.714  INFO 8 --- [           main] c.a.s.p.i.servlet.AwsServletContext      : Initializing Spring DispatcherServlet 'dispatcherServlet'

2023-02-22 11:19:02.732  INFO 8 --- [           main] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'

2023-02-22 11:19:02.735  INFO 8 --- [           main] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

START RequestId: ef81158e-cf35-4803-9f6c-a9812c544eb8 Version: $LATEST

2023-02-22 11:19:03.216 DEBUG 8 --- [           main] o.s.security.web.FilterChainProxy        : Securing GET /

2023-02-22 11:19:03.294 DEBUG 8 --- [           main] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext

2023-02-22 11:19:03.355 DEBUG 8 --- [           main] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext

2023-02-22 11:19:03.453 DEBUG 8 --- [           main] o.s.s.w.a.i.FilterSecurityInterceptor    : Failed to authorize filter invocation [GET /] with attributes [authenticated]


2023-02-22 11:19:03.473 DEBUG 8 --- [           main] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request

2023-02-22 11:19:03.475  INFO 8 --- [           main] c.a.s.p.internal.LambdaContainerHandler  : 127.0.0.1 null- null [09/04/2015:12:34:56Z] "GET / HTTP/1.1" 401 - "-" "Custom User Agent String" combined

Dependency:

    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
      <version>4.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

Configuration:

spring.cloud.azure.active-directory.enabled=true
spring.cloud.azure.activedirectory.client-id= url
spring.cloud.azure.activedirectory.client-secret=url
spring.cloud.azure.activedirectory.app-id-uri=url
spring.cloud.azure.activedirectory.tenant-id=url
jwk.provider.uri= URL

Code:

The class has configure method where it extending AadResourceServerWebSecurityConfigurerAdapter

       @Override
	protected void configure(HttpSecurity http) throws Exception {
		System.out.println("inside OAuth2");

		http.authorizeRequests().antMatchers("/").permitAll().anyRequest().authenticated().and().sessionManagement()
				.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().oauth2ResourceServer().jwt();

		System.out.println("getting outside OAuth2");
	}

Hi @abdulrais , it seems not a bug from the library side since you can run it locally successfully, but your scenario has not been verified.

According to your configuration, you should refer to the default implementation, which means you need to explicitly call this method super.configure(http) before your custom security configuration; or explicitly use the jwt authentication token converter from this method.

Could you provide a minimal sample to reproduce this scenario?

Hi @abdulrais you can further confirm the cause of the problem by inspecting the console log to verify the function app can access the Azure AD authorization server successfully and what permissions have been obtained.

Please turn the log level to debug level, after the resource server access the HTTP, you should find the below similar logs:

DEBUG 10836 - o.s.web.client.RestTemplate              : HTTP GET https://login.microsoftonline.com/<yout-tenant-id>/discovery/v2.0/keys
DEBUG 10836 - .a.i.j.AadJwtGrantedAuthoritiesConverter : User XXX's authorities created from jwt token: [SCOPE_XXXX].

Then the output authority set should contain the permissions you want to verify, otherwise, HTTP 401 will be returned.

thanks @moarychan for clarifying it. I was passing token in wrong headers since I need to pass in multiValueHeaders in aws lambda console. It is working currently and able to authenticate it.