Error enabling OAuth2 - spring

I am new to Spring Boot and trying to work with some of the example apps from Josh Long and Dave Syer.
I have the following code :
#SpringBootApplication
#EnableOAuth2Resource
#RestController
public class SsoResourceApplication {
#RequestMapping("/hi")
public Map<String, Object> hi(Principal principal) {
System.out.println("received request from " + principal.getName());
Map<String, Object> result = new HashMap<>();
result.put("id", UUID.randomUUID().toString());
result.put("content", "Hello, world!");
return result;
}
With the dependencies defined so
compile('org.springframework.security.oauth:spring-security-oauth2:2.0.8.RELEASE.jar')
compile('org.springframework.cloud:spring-cloud-starter-security:1.0.4.RELEASE')
When I start up I get the following error
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration':
Injection of autowired dependencies failed
Thanks in advance

It looks like you omitted the property spring.oauth2.resource.userInfoUri in your application.properties (or application.yml). This property must point to a URI within your authorization server. Here is a Spring boot 1.2 to 1.3 migration document.
I assume you have an authorization server in your environment, so that the user Info URI can point to.
You also migh want to have a look at the Spring boot OAuth2 tutorial.
Finally, you would see that most recent examples use #EnableResourceServer rather than #EnableOAuth2Resource. They are equivalent, but the former does not require a dependency on spring cloud and the configuration property is slightly different (security.oauth2.resource.userInfoUri). It's all explained in the Spring boot 1.2 to 1.3 migration document.

Related

spring boot 2 + netty + servlet.context-path + not working

I am trying to create a spring-boot-2 REST api using spring-boot-starter-webflux and reactive Netty. I am trying to set the context-path as per the new properties to be defined in application.yml defined in Spring-Boot-2.
server.servlet.context-path: /api # Define the server context path
However it looks like Webflux, Netty doesn't use/recognise this property defined in application.yml.
If I use spring-boot-starter-web and Tomcat as the default server then it works fine and recognises context-path properly.
Didn't find anything mentioned about Netty's context-path in Spring Boot 2 documentation.
Spring Boot Version = 2.0.3.RELEASE
Please let me know if I missed something or this is the default behaviour of Webflux Netty ?
Configuring the context path is servlet-specific. when using WebFlux,
the configuration property was renamed to server.servlet.context-path and only for servlet based deployment.
You can read below thread to how you can deal with context path in webflux, please see comment
https://github.com/spring-projects/spring-boot/issues/10129#issuecomment-351953449
Webflux Context path issue thread
In spring boot 2.3.x you can set spring.webflux.base-path property
It worked for me with
spring.webflux.base-path=/myPath
but only when adding the hint in this comment: https://stackoverflow.com/a/67840678/8376373
which suggests to inject a WebFluxProperties Bean
#Bean
fun webFluxProperties(): WebFluxProperties {
return WebFluxProperties()
}
You can use a WebFilter to work around this limitation:
#Autowired
lateinit var serverProperties: ServerProperties
#Bean
fun contextPathWebFilter(): WebFilter {
val contextPath = serverProperties.servlet.contextPath
return WebFilter { exchange, chain ->
val request = exchange.request
if (request.uri.path.startsWith(contextPath)) {
chain.filter(
exchange.mutate()
.request(request.mutate().contextPath(contextPath).build())
.build())
} else {
chain.filter(exchange)
}
}
}

Does Spring Boot Actuator have a Java API?

We customize the Spring Boot Actuator Info endpoint to include the application version number generated during our Jenkins build. We're using gradle to do this:
if (project.hasProperty('BUILD_NUMBER')) {
version = "${BUILD_NUMBER}"
} else {
version = "0.0.1-SNAPSHOT"
}
That works great for adding the version to the /info endpoint, but I'd like to access it when the application starts and print it to the application log.
I'm hoping the values are exposed in some property value (similar to spring.profiles.active) or through a Java API. That way, I could do something like this:
public class MyApplication{
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("spring.fancy.path.to.info.version"));
}
}
Looking through the docs, I'm not finding a way to access these values easily in code. Has anyone else had luck with this?
To get exactly the same properties of an actuator endpoint that are exposed through the REST endpoints, you can inject in one of your classes an instance of the respective endpoint class. In your case, the "right" endpoint class would be the InfoEndpoint. There are analogous endpoint classes for metrics, health, etc.
The interface has changed a little between Spring Boot 1.5.x and Spring Boot 2.x. So the exact fully qualified class name or read method name may vary based on the Spring Boot version that you are using. In Boot 1.5.x, you can find most of the endpoints in the org.springframework.boot.actuate.endpoint package.
Roughly, this is how you could build a simple component for reading your version property (assuming that the name of the property inside the info endpoint is simply build.version):
#Component
public class VersionAccessor {
private final InfoEndpoint endpoint;
#Autowired
public VersionAccessor(InfoEndpoint endpoint) {
this.endpoint = endpoint;
}
public String getVersion() {
// Spring Boot 2.x
return String.valueOf(getValueFromMap(endpoint.info()));
// Spring Boot 1.x
return String.valueOf(getValueFromMap(endpoint.invoke()));
}
// the info returned from the endpoint may contain nested maps
// the exact steps for retrieving the right value depends on
// the exact property name(s). Here, we assume that we are
// interested in the build.version property
private Object getValueFromMap(Map<String, Object> info) {
return ((Map<String, Object>) info.get("build")).get("version");
}
}

Spring Data MongoDB Configure Database bean

How to I configure the Mongo database bean? The bean is initialized by the MongoDB driver somehow with somethings pre-configured. I can't get the bean using mongoClient.getDatabase() because the database name either comes from the connection uri or just the standard property. And I can't define a new bean to update the old one like this public MongoDatabase mongoDatabase(MongoDatabase database) because that causes a ban definition cycle loop. What do I do?
Not entirely relevant to the question, but here's my intention:
What I trying to do is add custom Conventions introduced in MongoDB Driver version 3.6.
http://mongodb.github.io/mongo-java-driver/3.6/bson/pojos/
I know that spring data mongodb uses an older version, so I just replaced it with the newer one.
You need to take care of couple of things if you wish to configure MongoTemplate Or MongoDatabase yourself.
You need to disable spring boot's Mongo Auto Configuration. You can achieve this as show below.
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
You have to create MongoTemplate or MongoDatabase bean and register it with Spring application context(using #Bean).
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
ServerAddress server = new ServerAddress(host,port);
MongoClientOptions.Builder builder = MongoClientOptions.builder();
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(new XYZCodec(..)),
MongoClient.getDefaultCodecRegistry());
builder.codecRegistry(codecRegistry).build();
MongoClientOptions options = builder.build();
MongoClient mongoClient = new MongoClient(server,options);
return new SimpleMongoDbFactory(mongoClient, mongoDataBase);
}
Replace XYZCodec with the codec you want.

Spring Solr connection with Zookeeper using jaas.conf

I am migrating an existing java project to Spring Boot. It connects to Solr via Zookeeper.
It is throwing following error on startup.
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /clusterstate.json
This following configuration works on local, but on other environments Zookeeper requires some authentication (jaas.conf). How do I pass the jaas.conf to Spring Boot such that it can initialize SolrClient correctly?
#Configuration
#EnableSolrRepositories(basePackages = "com.search", multicoreSupport = true)
public class SolrConfig {
#Value("${spring.data.solr.zk-host}")
private String zkHost;
#Bean
public SolrClient solrClient() {
return new CloudSolrClient(zkHost);
}
#Bean
public SolrTemplate solrTemplate(SolrClient solrClient) throws Exception {
return new SolrTemplate(solrClient);
}
}
jaas.conf
Client {
org.apache.zookeeper.server.auth.DigestLoginModule required
username="some_username"
password="some_password";
};
I tried passing credentials as environment properties of zkDigestUsername and zkDigestPassword. In this case there was no exception during Spring Boot startup, but subsequent inserts/reads to Solr is not working.
Any help would be appreciated. Thanks much!
I was able to fix the issue by providing jaas config using the following JVM parameter.
-Djava.security.auth.login.config=/etc/zookeeper/conf/jaas.conf

Spring OAuth2 Requiring PlatformTransactionManager

I'm working on integrating Spring Security OAuth2 with JWT tokens into a Spring Boot project. My authentication server is configured similar to what is found in this sample project.
When the OAuth2 client performs the POST on /oauth/token it is unable to create the access token. The specific error logged is:
o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: NoSuchBeanDefinitionException, No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined
I've debugged it down to AbstractTokenGranter line 70 at the call to tokenServices.createAccessToken. I've not been able to easily debug further than that because this call actually goes through a proxy. It seems something in the configuration is wanting to make this transactional. Creating access tokens shouldn't be transactional in JWT. I could see why retrieving the access code would be transactional, but the code successfully gets past that point.
Why might this be requiring the PlatformTransactionManager and how can I supply one?
Problem is that you configured in your application a usage of a in-memory database with new InMemoryTokenStore(), but your spring-boot application contains no in-memory database.
Solution: add in your spring-boot pom or gradle dependency a in-memory database.
Example for H2 and Maven pom:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.187</version>
</dependency>
I had the same problem
tokenServices.createAccessToken use #Transactional .
As i use mongo DB i don't need transactions .
i solved the problem by adding a PseudoTransactionManager bean .
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new PseudoTransactionManager();
}
The problem is that methods in DefaultTokenServices are annotated with #Transactional. So even if you're not using a database, you'll need to add a transaction manager bean like this in your authorization server configuration:
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new ResourceTransactionManager() {
#Override
public Object getResourceFactory() {
return null;
}
#Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return null;
}
#Override
public void commit(TransactionStatus status) throws TransactionException {
}
#Override
public void rollback(TransactionStatus status) throws TransactionException {
}
};
}
I faced similar issue of PlatformTransactionManager and resolved it by the following steps:
Added H2 database to pom.xml (to enable storage of clients in memory)
Using Mongo DB as application backend. (ensured application uses MongoRepository instead of CrudRepository)
Removed exclude class in #EnableAutoConfiguration annotation (I had earlier added DataSourceAutoConfiguration.class in exclusion)
Point 1 and Point 3 are mutual. H2 configuration should have DataSourceAutoConfiguration.class enabled.
Thanks.

Resources