Should oauth2 Resource Server Interrogate Userinfo Endpoint on Authentication Server - spring-boot

When creating a resource server to protect my api endpoints in spring boot I am using spring-boot-starter-oauth2-resource-server and it does not try to pull back the claims from the userinfo endpoint on the authentication server. I am wondering if this is expected behavior and if so should I be using another library to setup spring security for my resource server? It appears debugging that this module pulls in the info from the well-known and should be able to easily know the userinfo endpoint.
This is the current dependencies that I am using maybe I am just missing some module that I am not aware of.
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>openid-resource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>openid-resource</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

NatFar's answer is right on the money, but I thought I'd add some color that I couldn't fit into a comment.
Indeed, Resource Server is about authorization, but the API provides hooks for you to be able to customize this, calling a userinfo endpoint being among them.
As of Spring Security 5.1:
#Override
protected void configure(HttpSecurity http) {
http
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(new MyConverter());
}
private static class MyConverter
implements Converter<Jwt, AbstractAuthenticationToken> {
#Override
public AbstractAuthenticationToken convert(Jwt jwt) {
// invoke the userinfo endpoint
// construct an Authentication statement from the response
}
}
Spring Security 5.1 only supports JWT, however in Spring Security 5.2 (which GAs in a couple of weeks) it supports opaque tokens as well. It also generalizes the representation a bit:
#Override
protected void configure(HttpSecurity http) {
http
.oauth2ResourceServer()
.opaqueToken()
.introspector(new MyIntrospector());
}
private static class MyIntrospector implements OpaqueTokenIntrospector {
#Override
public OAuth2AuthenticatedPrincipal introspect(String token) {
// invoke the userinfo endpoint
// construct an OAuth2AuthenticatedPrincipal from the response
}
}
I've added a ticket to get documentation added around your usecase; however, the JWT-introspection example that's already there is fairly close.

Check out what the Spring reference says about the resource server:
It’s atypical for a resource server to need to call a user info endpoint. This is because, fundamentally, a resource server is about authorizing a request, not authenticating it
Usually, it's the client application that queries the user info endpoint for more info about the user.
But the reference proceeds to show how to configure the resource server to call the user info endpoint if you're using the old Spring Security OAuth.
However, in Spring Security 5, it appears that you're only able to use the user info endpoint via .oauth2Client() or .oauth2Login().
The reference states that it's the client the makes a request for the user info.

Related

Stop sending Spring boot metrics to Prometheus with Micrometer

I have a Spring boot application where I am sending custom metrics generated within the service to Prometheus via Pushgateway.
I am using Prometheus Pushgateway with Micrometer, mainly based on this tutorial: https://luramarchanjo.tech/2020/01/05/spring-boot-2.2-and-prometheus-pushgateway-with-micrometer.html
I have following dependencies in my pom.xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
<version>0.16.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
And sending custom metrics with:
Counter counter = Counter.builder("sb_console_test_counter").register(meterRegistry);
counter.increment();
It is working fine and I can view the custom metrics generated by the application however in addition to this I am seeing application specific metrics generated by Spring boot e.g.
tomcat_sessions_active_current_sessions
tomcat_sessions_active_max_sessions
etc.
I only want to capture the custom metrics generated by my code and not any other generic metrics, how can I stop sending this?
When you add the dependency spring-boot-starter-actuator you will get a lot of metrics out of the box from various configurations such as JvmMetricsAutoConfiguration and TomcatMetricsAutoConfiguration.
To filter those out, you could add a deny filter in your Micrometer config, and only allow your custom metric meters to be registered.
Example using a deny filter:
#Bean
public MeterRegistryCustomizer<MeterRegistry> metricsRegistryConfig() {
return registry -> registry.config()
.meterFilter(MeterFilter.deny(id -> !id.getName().startsWith("sb_console")));
}
The above will deny any metrics not starting with sb_console.
See this link for more info about the meter filters
I believe you can just add this:
management.metrics.export.defaults.enabled=false
to your application.properties. I see this in some of my code. I'm not set up to try it right now, but that's why we have it there.
If you want to add back some of the built in metrics, you can then add lines like this:
management.metrics.export.<groupname>.enabled=true

Authentication with OAuth2 in Webflux Spring

I'm developing an app, in which i want to have role-based access control, unfortunately I didn't find any good example with spring webflux usage.
My oauth2.client.provider is Okta.
Here is my SecurityWebFilterChain:
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers("/*").permitAll()
.pathMatchers("/admin").hasRole("admins");
}
In this article I've found that I should configure resource server. Give me a hint how to do it,please.
You'll need to use a milestone release of Spring Boot 2.1 for this to work. M3 or higher should do the trick. Add the necessary dependencies for Spring Security 5.1 OIDC support:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
Then create an Okta OIDC "Web" app and copy your settings into src/main/resources/application.yml.
spring:
security:
oauth2:
client:
provider:
okta:
issuer-uri: https://dev-737523.oktapreview.com/oauth2/default
registration:
login:
okta:
client-id: {clientId}
client-secret: {clientSecret}
scope: openid email profile
Restart your app, go to http://localhost:8080, and you should be redirected to Okta to log in. Enter valid credentials, and you'll be redirected back to your app after a successful log in.
To limit access based on roles, you'll need to create groups for your users.
Create a ROLE_ADMIN and ROLE_USER group (Users > Groups > Add Group) and add users to them. You can use the account you signed up with, or create a new user (Users > Add Person). Navigate to API > Authorization Servers, click the Authorization Servers tab and edit the default one. Click the Claims tab and Add Claim. Name it “groups” or “roles”, and include it in the ID Token. Set the value type to “Groups” and set the filter to be a Regex of ".*" (to include them all).
Then you should be able to use something like:
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers("/*").permitAll()
.pathMatchers("/admin").hasAuthority("ROLE_ADMIN");
}
You should also be able to use #PreAuthorize as mentioned in this blog post.

Spring session with redis - lost Principal

guys.
I migrated to Spring session with Redis implementation. I'm using spring boot and the only thing that i've made to start with this implementation is to add this
<!-- Spring Session with Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- -->
in pom.xml and this in application.properties.
#Redis for session persistent
spring.session.store-type=REDIS
spring.redis.host=localhost
spring.data.redis.repositories.enabled=false
Everything is working fine, except that from time to time, the Principal (authneticated user is lost). I still have access to restricted pages, but Principal obejct is null. This leads to corrupted data, because I track the entries created from the speceific user.
Whan of the methods that have problem is:
public void addSamples(Integer distributorId, String articleNumber, Integer quantity, Principal user) {
Distributor distributor = distributorRepository.getOne(distributorId);
Tile tile = tileRepository.findByArticleNumber(articleNumber);
Merchandiser merchandiser = merchandiserRepository.findByUsername(user.getName());
Samples samples = new Samples();
samples.setMerchandiser(merchandiser);
samples.getSamplesPK().setDistributor(distributor);
samples.getSamplesPK().setTile(tile);
samples.setQuantity(quantity);
distributor.getSamples().add(samples);
distributorRepository.save(distributor);
}
I'm still logged and have access, but the merchandiser object is null..
What can be the reason for this ? Any help will be usefull.
Best regards.

Spring-boot actuator: only some endpoints work

I'm trying to implement spring-boot actuator for the first time but I've noticed that:
It only works if I specify the version, otherwise not;
Only a few endpoints works among those declared by the /actuator endpoint response.
This is the dependencies I've inserted in my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-docs</artifactId>
</dependency>
...
</dependencies>
This is my application.properties:
#info for Spring Boot Actuator
info.app.name=Spring Sample Application
info.app.description=Application to demonstrate Spring REST HATEOAS and Actuator
info.app.version=1.0.0
When I make this http request:
http://localhost:8080/actuator
it returns me:
{"links":[{"rel":"self","href":"http://localhost:8080/actuator"},{"rel":"loggers","href":"http://localhost:8080/loggers"},{"rel":"env","href":"http://localhost:8080/env"},{"rel":"info","href":"http://localhost:8080/info"},{"rel":"heapdump","href":"http://localhost:8080/heapdump"},{"rel":"mappings","href":"http://localhost:8080/mappings"},{"rel":"metrics","href":"http://localhost:8080/metrics"},{"rel":"configprops","href":"http://localhost:8080/configprops"},{"rel":"autoconfig","href":"http://localhost:8080/autoconfig"},{"rel":"beans","href":"http://localhost:8080/beans"},{"rel":"auditevents","href":"http://localhost:8080/auditevents"},{"rel":"trace","href":"http://localhost:8080/trace"},{"rel":"health","href":"http://localhost:8080/health"},{"rel":"dump","href":"http://localhost:8080/dump"},{"rel":"docs","href":"http://localhost:8080/docs"}]}
Among these links, only /health and /info seem to work.
In fact, when I ask for /health it returns:
{"status":"UP"}
When I ask for /info it returnes:
{"app":{"description":"Application to demonstrate Spring REST HATEOAS and Actuator","name":"Spring Sample Application","version":"1.0.0"}}
How comes that all the other endpoints gives me Whitelabel error page?
Did you try to see the logs when you try other endpoints. It says
Full authentication is required to access actuator endpoints. Consider adding Spring Security or set 'management.security.enabled' to false.
I guess this is self explanatory. Configure atleast basic auth or set the above mentioned property to false.
Whitelabel error page that you see also says
There was an unexpected error (type=Unauthorized, status=401).
Here is the link for the doc related to this.
In my case I was getting 404 Whitelabel Error Page because only /actuator/health and /actuator/info are the only endpoints enabled by default (as mentioned on the Spring Boot Actuator documentation)
To enable the other endpoints I ended up adding this configuration to my application.yml:
management:
endpoints:
web:
exposure:
include: info, health, loggers, logfile, configprops
I found a posting at Baeldung where it says
Unlike in previous versions, Actuator comes with most endpoints disabled. (Link)
So add management.endpoints.web.exposure.include=*. to your application.properties.

How to combine Feign and OAuth 2.0?

I'm using Spring Feign and Oauth 2.0
My application has
1 Api gateway with #EnableOAuth2Sso
2 Services with #EnableResourceServer
When I call an api of an service from the other service, I get this exception.
feign.FeignException: status 401 reading TestFeign#test(); content:
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
How to call an api of an service from the other service?
For services you can use these dependency.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>feign-oauth2-spring-cloud-starter</artifactId>
<version>1.0.0</version>
</dependency>
This way does not work for api gateway!!!

Resources