Injecting springSecurityService into Controller with Grails 3.0.3 - spring

I am trying to get current user inside a controller in a Grails 3.0.3 application.
I have used this repo as a base for my security setup - security is GORM based. I am using following line in build.gradle in order to include Spring Security Framework:
compile "org.springframework.boot:spring-boot-starter-security"
but when I try to inject springSecurityService like it was recommended in other SO threads (see for example: this one) in my controller, I get only a null object. It is not initiated like it should be.
class RestapiController {
def springSecurityService
def currentUser(){
def user = springSecurityService.currentUser
render user
}
}
How can I inject springSecurityService into a controller in Grails 3.0.3?
UPDATE:
In the end I used following line to get the current user:
SecurityContextHolder.context.authentication.name

springSecurityService isn't part of Spring Security, it's in the Grails spring-security-core plugin. Spring Security doesn't have the concept of the "current user". You can access the current Authentication and get the username, password, enabled, etc., but there's nothing in the framework that gets you back to the source object that was used to populate the authentication (in Grails + spring-security-core this is often a User domain class instance) - that would have to be done in your application code.
This weekend I released an initial version of the plugin that works with Grails 3, version 3.0.0.M1. The documentation is here. There's a short tutorial in the docs to help get you started, and you might also check out this sample app using the plugin in Grails 3.

Related

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.

How to access keycloak with the admin-client?

I'm trying to change roles of a user in keycloak with the keycloak-admin-client in a spring boot application, but I can't even instanciate keycloak.
I'm trying to get the keycloak server here, but Im getting a InstantiationError
String serverUrl = "http://localhost:8080/auth";
String realm = "User-Service-Realm";
String clientId = "admin-cli";
Keycloak keycloak = Keycloak.getInstance(
serverUrl,
realm,
"admin",
"admin",
clientId);
Exception in thread "main" java.lang.InstantiationError: org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
at org.keycloak.admin.client.Keycloak.<init>(Keycloak.java:58)
at org.keycloak.admin.client.Keycloak.getInstance(Keycloak.java:106)
at de.uni.stuttgart.isw.ccm.userservice.api.KeycloakAdminClientExample.main(KeycloakAdminClientExample.java:31)
Apparently its a problem with the admin-client itself, since the keycloak builder is based on the resteasyclientbuilder.
You seem to have incompatible libraries or library versions. The error message complains that ResteasyClientBuilder is abstract. That not the case in our working project.
So as a reference, here is an extract from our gradle file so you can see a working combination of library versions:
implementation 'org.keycloak:keycloak-admin-client:6.0.1'
implementation 'javax.ws.rs:javax.ws.rs-api:2.0'
implementation 'org.jboss.resteasy:resteasy-jaxrs:3.6.3.Final'
implementation 'org.jboss.resteasy:resteasy-client:3.6.3.Final'
implementation 'org.jboss.resteasy:resteasy-jackson2-provider:3.6.3.Final'
Update:
ResteasyClientBuilder has become an abstract class with version 4.0 of RESTEasy. So it looks as if you are using version 4.x, while Keycloak expects 3.x.

How to use Apache Shiro for authorization only?

Before I explain the issue I should say that we only need Apache Shiro for authorization and athentication is already enabled with OAuth2.
So my code to enable Shiro is exactly as the code in this link here.
I have also checked this issue. But for me if I enable LifecycleBeanPostProcessor almost most beans will be null. I made that create method in config class static as it suggests in the second link but no luck.
So my question is, is there any way to only enable authorization without registering shiro filter? If not, how to get around this issue? Because it seems ShiroFilterFactoryBean requires LifecycleBeanPostProcessor and that breaks the whole application.
We are using latest version of Spring Boot and Shiro 1.2.4
As outlined in an issue in the comments, you would need to set an already authenticated identity in the subject, which can be done with the Subject.Builder() (I'm using version 1.5.2 here).
Subject user = new Subject.Builder()
.principals(new SimplePrincipalCollection("bud", "myRealm"))
.authenticated(true)
.buildSubject();
if (user.hasRole("admin")) {
// do some authorized stuff
}
When implementing a custom realm the authentication ability can be disabled by returning false from the Realm’s supports method as described here .

How to disable the UsernamePasswordAuthenticationFilter in Spring Security 4

I'm migrating a JSF application from Spring Security 3.2 to 4.0.1. This version changes many default urls, for example the default login url to /login.
The application has its own login page (using JSF AJAX) and it is still displayed when calling /login, but all POST-Requests to this URL (and so all AJAX-Requests from the Login-Page) are captured by the UsernamePasswordAuthenticationFilter and that is trying to process the authentication, causing the request to get redirected to the loginform again.
After looking at the code this url seems to be hard-coded:
public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
So I have to disable this filter completely, or better, avoid it's creation. Can anybody point me how I can do it.
Changing my login page to another url is working, but is not the nice solution.
EDIT: I have created a Bugticket in Spring Security for this: https://jira.spring.io/browse/SEC-2992
EDIT 2: I've found another workaround: If I set the login-processing-url for the form-login to something unused it is working, but seems to be very hacky. There should be a way to disable it completely. Also it should be stated in the migration guide, I lost hours until I found this.
I am going to assume that you are trying to upgrade to Spring Security 4.0.0 (the latest available version is 4.0.1).
Spring Security 3.x used spring_security_login as the default login URL (source: official documentation). This could be set to a custom value as <security:form-login login-page="/login"> and mapped to a controller to render a custom page.
Spring Security 4.x has abandoned spring_security_login and switched to login as the default login URL (source: official Spring Security 4.x migration guide). Therefore, the URL login now goes to the default Spring Security infrastructure, that displays the default, auto-generated login page.
There was a bug in 4.0.0 due to which the default infrastructure was still getting used in cases where the URL /login was manually mapped to a custom controller method. This bug has been fixed in 4.0.1. Do try upgrading to Spring Security 4.0.1 to see if you can use /login as the login URL.
It looks like you could call setFilterProcessesUrl(String) (or, equivalently, setRequiresAuthenticationRequestMatcher(RequestMatcher)) to override the default of /login.

Using simple auth and form based access to controllers

Suppose I have a Grails 2.4.3 application, with one controller:
#Secured(['ROLE_USER'])
Class HeyController {
def doSomething() { render "Do something" }
def doSomethingElse() { render "Do something else" }
}
I would like to tell the underlying Spring Security framework to secure access like so:
Form based login for http://myhost:8080/app/hey/doSomething
Basic HTTP authentication for http://myhost:8080/app/hey/doSomethingElse
I know it's possible to configure this access using vanilla Spring security using two <http> configuration sections for each access pattern in the security context configuration file.
Therefore, there must be some way to setup Spring Security via Grails right? Thanks!
... nevermind facepalm. It seems to be the case:
http://grails-plugins.github.io/grails-spring-security-core/guide/authentication.html
I'll mark the answer as soon as I get it working in practice. Thanks!

Resources