Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' available #258

Closed
1 of 2 tasks
srajiang opened this issue Mar 11, 2021 · 17 comments

Comments

@srajiang
Copy link

srajiang commented Mar 11, 2021

👋 Hello, I was directed to submit this as an issue after troubleshooting with Lijia on the Dev Support team. I am hoping this is an environment / configuration issue on my end (I am new to Java / Spring) and not a bug, so I've provided details below on what I have set up as well for context.

I'm submitting a

  • bug report
  • feature request

Background info

I am writing an API and my goal is to be able to validate the access token (JWT) passed to it from a client application with the help of okta-spring-boot-starter and Okta as the default authorization server. This is a Spring Boot Application (backend). The AP client sending the access tokens as part of Bearer is isolated and gets its tokens separately via the Authorization Code flow with PCKE.

Issue

With okta-spring-boot-starter as a dependency, the application is failing to start with this error:

Screen Shot 2021-03-10 at 4 35 09 PM

OIDC App Details

  • client id: 0oaq60t2y0hSwuaHR0x7
  • client authentication: use PKCE
  • allowed grant types: Authorization code

Application Properties

Here is my application.properties file:

okta.oauth2.issuer=https://{issuer domain} <---- omitted just for privacy purposes
okta.oauth2.client-id=0oaq60t2y0hSwuaHR0x7
server.port=8081

When I run this with https://{issuer domain}/oauth2/default as described in the instructions, the application fails earlier in the run with this error.

Caused by: java.lang.IllegalArgumentException: Unable to resolve Configuration with the provided Issuer of "https://slackcorp.okta.com/oauth2/default"

which leads me to believe that the properties I have set up are correct. I'm under the impression that I should be able to use the same value for issuer as what I see in the access token and that value also matches what I currently have for okta.oauth2.issue. Additionally https://{ issuer domain }/.well-known/openid-configuration is accessible via curl and in the browser and returns the application meta data I expect.

I have omitted the client-secret field as my application uses PKCE, and based on this it seems like it's not necessary anymore.

Dependencies

Very straightforward as this is a test project.
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.3.1.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>demo</name>
   <description>Demo Project to Test Okta Spring Integration</description>
   <properties>
      <java.version>11</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>com.okta.spring</groupId>
         <artifactId>okta-spring-boot-starter</artifactId>
         <version>2.0.1</version>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

WebSecurityConfigurerAdapter

Also following instructions, I have set up this class:
com.example.demo.config.WebSecurityConfig

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

        http.authorizeRequests()
                // allow anonymous access to the root page
                .antMatchers("/").permitAll()
                // other requests
                .anyRequest().authenticated()
                .and()
                // creates a BearerTokenAuthenticationFilter to intercept requests, extract bearer token jwt
                .oauth2ResourceServer().jwt();

        //Sends 401 response to client for unauthorized requests
        Okta.configureResourceServer401ResponseBody(http);
    }
}

Application

@SpringBootApplication(scanBasePackages = {"com.example.demo"})
@RestController
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

/**

  • Simple example REST endpoint that returns a static message. This controller also serves as an example for checking
  • an OAuth scope and client roles (parsed from an access token).
  • @return a static welcome message
    */
    @GetMapping("/hello-auth")
    public String hello(@AuthenticationPrincipal OidcUser user) {
    return "Hello, " + user.getFullName();
    }

@GetMapping("/hello-world")
public String helloWord() { return String.format("Hello World"); }
}

Expected behavior

I expect that the application should build and run successfully without errors, given the basic configuration I have outlined above.

What went wrong?

An exception is thrown as the required HttpSecurity bean is not available. I think I have followed the setup instructions for the SDK, but it's possible I have misconfigured something.

Steps to reproduce

  1. Use Spring initializer to start a new Spring project (see pom.xml for dependencies)
  2. Add the application.properties
  3. Add the WebSecurityConfigurerAdapter
  4. mvn clean install

SDK Version

2.0.1

@srajiang
Copy link
Author

And here's the full stack trace:

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

2021-03-10 16:45:19.870  INFO 69634 --- [           main] com.example.demo.DemoApplicationTests    : Starting DemoApplicationTests on SFO-M-SARAHJIANG01 with PID 69634 (started by sarahjiang in /Users/sarahjiang/Desktop/de/Slack.0 Server/testSpringOkta)
2021-03-10 16:45:19.872  INFO 69634 --- [           main] com.example.demo.DemoApplicationTests    : No active profile set, falling back to default profiles: default
2021-03-10 16:45:21.919  INFO 69634 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@73afe2b7, org.springframework.security.web.context.SecurityContextPersistenceFilter@234c5e41, org.springframework.security.web.header.HeaderWriterFilter@5d1b1c2a, org.springframework.security.web.csrf.CsrfFilter@553da911, org.springframework.security.web.authentication.logout.LogoutFilter@6b9fdbc6, org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@1039bfc4, org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@e700eba, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@3a36cd5, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@9687f55, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@654e6a90, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@461c3709, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@6435fa1c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5700c9db, org.springframework.security.web.session.SessionManagementFilter@72bd2871, org.springframework.security.web.access.ExceptionTranslationFilter@7ebe2e47, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@40709f9]
2021-03-10 16:45:22.255  INFO 69634 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-10 16:45:22.330  INFO 69634 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [public/index.html]
2021-03-10 16:45:22.413  WARN 69634 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oauth2SecurityFilterChain' defined in class path resource [com/okta/spring/boot/oauth/OktaOAuth2AutoConfig$OAuth2SecurityFilterChainConfiguration.class]: Unsatisfied dependency expressed through method 'oauth2SecurityFilterChain' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2021-03-10 16:45:22.414  INFO 69634 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2021-03-10 16:45:22.420  INFO 69634 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-03-10 16:45:22.510 ERROR 69634 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method oauth2SecurityFilterChain in com.okta.spring.boot.oauth.OktaOAuth2AutoConfig$OAuth2SecurityFilterChainConfiguration required a bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' in your configuration.

2021-03-10 16:45:22.517 ERROR 69634 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@c7045b9] to prepare test instance [com.example.demo.DemoApplicationTests@19fbc594]

java.lang.IllegalStateException: Failed to load ApplicationContext
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:341) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:346) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:341) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na]
        at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
        at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) ~[na:na]
        at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[na:na]
        at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) ~[na:na]
        at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) ~[na:na]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:340) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:263) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:256) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at java.base/java.util.Optional.orElseGet(Optional.java:362) ~[na:na]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:255) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:108) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:107) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:71) ~[junit-jupiter-engine-5.6.2.jar:5.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) ~[junit-platform-engine-1.6.2.jar:1.6.2]
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
        at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
        at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:150) ~[surefire-junit-platform-2.22.2.jar:2.22.2]
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:124) ~[surefire-junit-platform-2.22.2.jar:2.22.2]
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384) ~[surefire-booter-2.22.2.jar:2.22.2]
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345) ~[surefire-booter-2.22.2.jar:2.22.2]
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126) ~[surefire-booter-2.22.2.jar:2.22.2]
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418) ~[surefire-booter-2.22.2.jar:2.22.2]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oauth2SecurityFilterChain' defined in class path resource [com/okta/spring/boot/oauth/OktaOAuth2AutoConfig$OAuth2SecurityFilterChainConfiguration.class]: Unsatisfied dependency expressed through method 'oauth2SecurityFilterChain' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:797) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:538) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:893) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
        at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) ~[spring-boot-test-2.3.1.RELEASE.jar:2.3.1.RELEASE]
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        ... 65 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.web.builders.HttpSecurity' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1714) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1270) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        ... 84 common frames omitted

@arvindkrishnakumar-okta
Copy link
Contributor

Thanks for the question!

  • Are you behind a firewall/proxy?
  • Are you able to hit the endpoint https://slackcorp.okta.com/oauth2/default/.well-known/openid-configuration from a browser?

@srajiang
Copy link
Author

@arvindkrishnakumar-okta

  • Firewall/proxy: No I don't believe I am.
  • Endpoint: No, I get an error message saying I'm not authorized to access:
{"errorCode":"E0000015","errorSummary":"You do not have permission to access the feature you are requesting","errorLink":"E0000015","errorId":"oaeTm32766WRVynJKjNkbkIcg","errorCauses":[]}

@arvindkrishnakumar-okta
Copy link
Contributor

arvindkrishnakumar-okta commented Mar 11, 2021

Since you're trying with a corporate production org, you may need to create your Authorization Server and you will need to get API Access Manager as a Product.

Try out your code with the developer account org and it should work. See signup instructions at developer.okta.com. Or, try out the Okta CLI tool.

@srajiang
Copy link
Author

srajiang commented Mar 11, 2021

@arvindkrishnakumar-okta - I am able to get an access token from the issuer I have provided without having to set up a custom authorization server in a separate flow.

I am trying to use that same issuer now for validating the token. Are you saying I have to have a separate Okta Authorization server setup just for validation?

Also if I can hit https://slackcorp.okta.com/.well-known/openid-configuration is that sufficient?

@arvindkrishnakumar-okta
Copy link
Contributor

arvindkrishnakumar-okta commented Mar 11, 2021

Accessing https://slackcorp.okta.com/oauth2/default/.well-known/oauth-authorization-server suggests that the default issuer does not exist for your corporate org. Try decoding your access token JWT using https://token.dev/ and see what the iss (issuer) claim is set to and you should be using that issuer.

@srajiang
Copy link
Author

@arvindkrishnakumar-okta - Okay, I checked the token and the iss claim value in the token is set to slackcorp.okta.com. I'm reading on this issue here @bdemers mentioned that the token might be the root Okta issuer and not able to be validated

Ahh, the issuer is the problem. This type of toke is from the root Okta issuer, and cannot be validated as a JWT (even though it is formatted as one). You need to use one formatted as I mentioned above.

And should be in this format:

https://${yourOktaDomian}/api/v1/authorizationServers/${id} (where id is usually the word "default")

Is that still the case?

@arvindkrishnakumar-okta
Copy link
Contributor

arvindkrishnakumar-okta commented Mar 11, 2021

@arvindkrishnakumar-okta - Okay, I checked the token and the iss claim value in the token is set to slackcorp.okta.com. I'm reading on this issue here @bdemers mentioned that the token might be the root Okta issuer and not able to be validated

Ahh, the issuer is the problem. This type of toke is from the root Okta issuer, and cannot be validated as a JWT (even though it is formatted as one). You need to use one formatted as I mentioned above.

And should be in this format:

https://${yourOktaDomian}/api/v1/authorizationServers/${id} (where id is usually the word "default")

Is that still the case?

Yes. Note that for root issuer, Okta Spring boot SDK (versions 2.0.0+) will attempt to validate the token remotely by making an API call to the introspect endpoint (https://slackcorp.okta.com/oauth2/v1/introspect).

@srajiang
Copy link
Author

srajiang commented Mar 11, 2021

@arvindkrishnakumar-okta - So if it's trying to validate the token remotely, is it still reasonable to expect to be able to use this issuer or should I be trying to setup that custom authorization server? I'm unclear on whether using slackcorp.okta.com here is valid?

The original issue I raised was about another error that occurred during runtime, related to a missing bean. in that case I had the issuer set to slackcorp.okta.com.

I really appreciate all your help by the way! 🙇‍♀️

@arvindkrishnakumar-okta
Copy link
Contributor

arvindkrishnakumar-okta commented Mar 11, 2021

@srajiang
Copy link
Author

srajiang commented Mar 11, 2021

@arvindkrishnakumar-okta Read the documentation, can you confirm:

Org Authorization Server
Every Okta org comes with a built-in authorization server called the Org Authorization Server. The base URL for the Org Authorization Server is https://${yourOktaOrg}.

You use the Org Authorization Server to perform SSO with Okta for your OpenID Connect apps or to get an access token for the Okta APIs. You can't customize this authorization server with regards to audience, claims, policies, or scopes. Additionally, the resulting access token's issuer is https://${yourOktaOrg}, which indicates that only Okta can consume or validate it. The access token can't be used or validated by your own applications.

This means that even with okta-spring-boot-starter I cannot validate the token I have? I seems to suggest that Okta can validate with that issuer? I'm try to request that Okta validate the token I have with that issuer.

@arvindkrishnakumar-okta
Copy link
Contributor

@bdemers
Copy link
Contributor

bdemers commented Mar 11, 2021

Hi @srajiang!

You should be able to validate the access token as an "opaque" token instead of a JWT. However, as @arvindkrishnakumar-okta mentioned usually for API use cases where you want to validate the token locally (i.e. a JWT) you would want to use a different Authorization Server that is setup for this.

You can configure Spring Security to use opaque tokens by doing something like:

import com.okta.spring.boot.oauth.Okta;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

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

        http.authorizeRequests()
            // allow anonymous access to the root page
            .antMatchers("/").permitAll() // for pure API use cases you can remove this
            // all other requests
            .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer().opaqueToken();

        // (optional) Send a 401 message to the browser (w/o this, you'll see a blank page)
        Okta.configureResourceServer401ResponseBody(http);
    }
}

Taking a step back, though, how are you getting your access token (we might be able to suggest an alternative there, so you can avoid using opaque tokens)

@srajiang
Copy link
Author

srajiang commented Mar 12, 2021

@bdemers Thanks for chiming in! I'll answer the stepping back question first, since it seems like we might be able to avoid using opaque tokens. Might be overdoing it on the detail here, but I thought I'd include everything just in case:

I have a totally separate application frontend (React / nodejs) that has the @okta-auth-js and @okta-react modules installed. I use the useOktaAuth hook from the latter and the member it provides, oktaAuth to .getUser(). The access token and id token that gets put in localStorage is what I've been referring to as my JWT / access token.

Here are the properties I have setup for that frontend app:

OKTA_BASE_URL_PROD=https://slackcorp.okta.com
OKTA_CLIENT_ID_PROD=0oaq60t2y0hSwuaHR0x7
REDIRECT_URI_DEV=http://localhost:8080/login/callback

So I guess with the properties configured this way, I'm directing the okta sdk to use the root issuer(?) for this first flow to get an access token. Should I not be doing that?

@srajiang
Copy link
Author

srajiang commented Mar 12, 2021

@bdemers Keeping all other things about my Spring environment setup constant (i.e. issuer as slackcorp.okta.com), I tried just changing the token type from .jwt() to .opaqueToken() inside the WebSecurityConfigurerAdapter, and got the following errors

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

2021-03-11 17:46:25.947  INFO 29091 --- [           main] com.example.demo.DemoApplicationTests    : Starting DemoApplicationTests on SFO-M-SARAHJIANG01 with PID 29091 (started by sarahjiang in /Users/sarahjiang/Desktop/de/Slack.0 Server/testSpringOkta)
2021-03-11 17:46:25.949  INFO 29091 --- [           main] com.example.demo.DemoApplicationTests    : No active profile set, falling back to default profiles: default
2021-03-11 17:46:27.711  WARN 29091 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector' available
2021-03-11 17:46:27.725  INFO 29091 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-03-11 17:46:27.849 ERROR 29091 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type 'org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector' that could not be found.

The following candidates were found but could not be injected:
        - Bean method 'opaqueTokenIntrospector' in 'OktaOAuth2ResourceServerAutoConfig' not loaded because AllNestedConditions 2 matched 1 did not; NestedCondition on OktaOpaqueTokenIntrospectConditional.IssuerCondition @ConditionalOnProperty (okta.oauth2.issuer) matched; NestedCondition on OktaOpaqueTokenIntrospectConditional.ClientSecretCondition @ConditionalOnProperty (okta.oauth2.client-secret) did not find property 'okta.oauth2.client-secret'; NestedCondition on OktaOpaqueTokenIntrospectConditional.ClientIdCondition @ConditionalOnProperty (okta.oauth2.client-id) matched
        - Bean method 'opaqueTokenIntrospector' in 'OAuth2ResourceServerOpaqueTokenConfiguration.OpaqueTokenIntrospectionClientConfiguration' not loaded because @ConditionalOnProperty (spring.security.oauth2.resourceserver.opaquetoken.introspection-uri) did not find property 'spring.security.oauth2.resourceserver.opaquetoken.introspection-uri'


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector' in your configuration.



rest omitted for brevity

@arvindkrishnakumar-okta
Copy link
Contributor

@srajiang you're missing to set the client secret above. You need the client secret to be able to validate opaque token.

@arvindkrishnakumar-okta
Copy link
Contributor

Closing this, feel free to reopen in case there are followup questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants