Is it a good idea to handle optional JWT Authentication in Filter? - spring

I am new to Spring Boot and my current project is a REST API developed in Spring Webflux. The goal is to have an endpoint which has an optional JWT Token, allowing you ti create things anonymously or not. But all the starter guides to Spring Security are really complicated and use Spring MVC, as far as I can tell.
Now my idea was to create a HandlerFilterFunction looking like
class AuthenticationFilter : HandlerFilterFunction<ServerResponse, ServerResponse> {
override fun filter(request: ServerRequest, next: HandlerFunction<ServerResponse>): Mono<ServerResponse> {
val authHeader = request.headers().header("Authorization").firstOrNull()
// get user from database
request.attributes()["user"] = user
return next.handle(request)
}
}
and adding it to the router {...} bean.
Is this a good idea, or should I go another router? If so, can somebody point me towards a JWT tutorial for Spring Webflux.

The Spring Security docs point to a JWT-Based WebFlux Resource Server sample in the codebase.
It's not Kotlin-based, so I also posted a sample of my own just now; hopefully, it helps get you started.
As for your question, yes, you can create a filter of your own, though Spring Security ships with a BearerTokenAuthenticationFilter that already does what your filter would likely do. The first linked sample adds this filter manually while the second sample lets Spring Boot add it.

Related

Spring Security Manual login/logout Transaction

Currently, im developing a Spring Security Project and im trying to login to the user manually. For management this case i have tried implement the "UserDetailsService" class in config file
#Bean
InMemoryUserDetailsManager getInMemoryUserDetailsManager(){
return new InMemoryUserDetailsManager();
}
After that, i tried to access this class with #Autowired annotation in a manager class. It's working on compile time but in any request arrested to endpoint. It returning 403(Forbidden Error) any authenticated endpoint. I'm trying figure it out for 2 days. Please help me about this subject. Thanks for any help!
Here is my project link : InMemoryAuth
Note: I tried to set up a new structure in this area, unlike other projects. So I may have done different injections in some parts.

Spring Boot 2.3.4: Bug with JwtValidators.createDefaultWithIssuer(String)?

I found an odd behavior with JWT parsing and JwtValidators.
Scenario:
Spring Boot OIDC client (for now a tiny web app, only displaying logged in user and some OIDC objects provided by Spring)
Custom JwtDecoderFacotry<ClientRegistration> for ID-Token validation
JwtValidatorFactory based on JwtValidators.createDefaultWithIssuer(String)
This worked well with Spring Boot version <= 2.2.10.
Debugging:
NimbusJwtDecoder (JAR spring-security-oauth2-jose) uses claim set converters. The 'iss' (issuer) claim is handled as URL.
JwtIssuerValidator (internally created by JwtValidators.createDefaultWithIssuer(String)) wraps a JwtClaimValidator<String>.
this one finally calls equals() that is always false - it compares String with URL.
My current workaround is not calling JwtValidators.createDefaultWithIssuer() but just using the validators new JwtTimestampValidator() and an own implementation of OAuth2TokenValidator<Jwt> (with wrapping JwtClaimValidator<URL>).
Anyone else having trouble with this?
--Christian
It's a bug. Pull Request is created.

Implement multi-tenanted application with Keycloak and springboot

When we use 'KeycloakSpringBootConfigResolver' for reading the keycloak configuration from Spring Boot properties file instead of keycloak.json.
Now there are guidelines to implement a multi-tenant application using keycloak by overriding 'KeycloakConfigResolver' as specified in http://www.keycloak.org/docs/2.3/securing_apps_guide/topics/oidc/java/multi-tenancy.html.
The steps defined here can only be used with keycloak.json.
How can we adapt this to a Spring Boot application such that keycloak properties are read from the Spring Boot properties file and multi-tenancy is achieved.
You can access the keycloak config you secified in your application.yaml (or application.properties) if you inject org.keycloak.representations.adapters.config.AdapterConfig into your component.
#Component
public class MyKeycloakConfigResolver implements KeycloakConfigResolver {
private final AdapterConfig keycloakConfig;
public MyKeycloakConfigResolver(org.keycloak.representations.adapters.config.AdapterConfig keycloakConfig) {
this.keycloakConfig = keycloakConfig;
}
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
// make a defensive copy before changing the config
AdapterConfig currentConfig = new AdapterConfig();
BeanUtils.copyProperties(keycloakConfig, currentConfig);
// changes stuff here for example compute the realm
return KeycloakDeploymentBuilder.build(currentConfig);
}
}
After several trials, the only feasible option for spring boot is to have
Multiple instances of the spring boot application running with different spring 'profiles'.
Each application instance can have its own keycloak properties (as it is under different profiles) including the realm.
The challenge is to have an upgrade path for all instances for version upgrades/bug fixes, but I guess there are multiple strategies already implemented (not part of this discussion)
there is a ticket regarding this problem: https://issues.jboss.org/browse/KEYCLOAK-4139?_sscc=t
Comments for that ticket also talk about possible workarounds intervening in servlet setup of the service used (Tomcat/Undertow/Jetty), which you could try.
Note that the documentation you linked in your first comment is super outdated!

Does spring security use AOP internally?

I hear that AOP can be used for separating cross cutting aspects like security, transaction and logging etc.
So, I want to understand that if spring security internally uses AOP ?
Yes, Spring Security uses AOP internally. For example, it is used for global method security. Global method security is used to apply security checks to certain methods (for example, in service layer).
You can find the following code in GlobalMethodSecurityBeanDefinitionParser that is a part of Spring Security infrastructure relating to global method security:
if (useAspectJ) {
BeanDefinitionBuilder aspect =
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
aspect.setFactoryMethod("aspectOf");
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
aspect.addPropertyValue("securityInterceptor", interceptor);
String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
} else {
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
}
It mentions AOP almost in every line.
More information on global method security may be found, for example, here https://docs.spring.io/spring-security/site/docs/3.0.x/reference/ns-config.html and here https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/

How to test REST in spring app with spring security

I've got spring web application with jersey rest services. However rest is secured via spring security and login process is very hard to perform from unit test code. I'd like to test rest services with whole spring security disabled. Is it even possible?
One of the advantages of annotation based web services is that you can unit-test them easily.
class WebServiceEndpoint {
#Path("/foo/{fooId}")
#POST
#Produces({ MediaType.APPLICATION_XML })
public Response doFoo(#PathParam("fooId") Integer fooId) {
/// ... web service endpoint implementation
}
}
If you're using Spring's servlet filter for security, then there shouldn't be any security-related code in the doFoo method, so you can just create a new WebServiceEndpoint class and call the method. So that's one way of 'disabling' security.
When you say the login process is 'hard', what do you mean? If you've succeeded in logging in once, then you can just reuse the same code in your other unit tests (e.g. in a #Before method).
Just test it as a pojo. Pass in whatever, return whatever, don't load an app context at all - that would be an integration test.
The ability to easily test functionality without the framework loaded is one of the key advantages of spring.
You don't say what's "hard," so I'm assuming that you've got something in your REST service, i.e. in the java method that you want to test, which requires authentication results. Spring has utilities for mocking the authentication results. For example, you can do the following in a #Before setup method:
Object principal = null; // fix this
Object credentials = null; // fix this
Authentication auth = new org.springframework.security.authentication.TestingAuthenticationToken(principal, credentials);
SecurityContextHolder.getContext().setAuthentication(auth);
But again, you haven't said what problem you're actually trying to solve...

Resources