The application I have in works uses Grails 3. I am attempting to do Pre-Authentication, as described in this article , but am having a hard time as I cannot figure out how to disable the regular authentication provided by the grails 3 spring security plugin.
Here is my current scenario: User A hits my webpage. I want to parse the headers of the request and take out the roles and username information. If the username or roles are empty, I will redirect the user to some gateway. In simple terms, I want to use spring security for authorization only, by invoking the static rules provided by the plugin. i.e
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/serviceb/**', access: "hasAnyRole('ROLE_COOL','ROLE_UNCOOL')"],
[pattern: '/cools/**', access: ['ROLE_ADMINS']],
[pattern: '/*', access: 'isAuthenticated()']
]
This is the reason I do not need spring security to do any login functionality, as the first article states, we can use it for authentication only.
What I have tried:
First, I removed all authentication related calls in my application.groovy file (created by default when running the quick start for the plugin) i.e, connection strings, search filters, but not static rules
Next, I tried to use a solution provided by these two posts: on stack and this on blog.
I created a Filter to extend the AbstractPreAuthenticatedProcessingFilter
package Cool.service.authentication
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter
import javax.servlet.http.HttpServletRequest
class CGAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { "username" }
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) { "N/A" }
}
My Boot config now looks like this:
import grails.plugin.springsecurity.SecurityFilterPosition
import grails.plugin.springsecurity.SpringSecurityUtils
class BootStrap {
def init = { servletContext ->
SpringSecurityUtils.clientRegisterFilter('CGAuthenticationFilter', SecurityFilterPosition.PRE_AUTH_FILTER.order)
}
}
And my Spring resources look like this:
import Cool.service.authentication.CGAuthenticationFilter
beans = {
myAuthenticationFilter(CGAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
checkForPrincipalChanges = true
}
}
And lastly, added this line to my application.groovy configuration for spring security plugin:
grails.plugin.springsecurity.providerNames = ['preAuthenticatedAuthenticationProvider', 'anonymousAuthenticationProvider']
However, I am getting a super geneirc error when trying to run-app, where the server "fails" to start and java returns a non zero value back. This makes me believe I am headed in the wrong direction, and the implementation is completely wrong
To solve the problem, I had to change a few files. First, my Bootstrap file now contains the following init block:
SpringSecurityUtils.clientRegisterFilter('requestHeaderAuthenticationFilter', SecurityFilterPosition.PRE_AUTH_FILTER)
My beans (resources.groovy) file now contains:
userDetailsService(grails.plugin.springsecurity.userdetails.GormUserDetailsService) {
grailsApplication = ref('grailsApplication')
}
userDetailsByNameServiceWrapper(org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper) {
userDetailsService = ref('userDetailsService')
}
preAuthenticatedAuthenticationProvider(org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = userDetailsByNameServiceWrapper
}
requestHeaderAuthenticationFilter(Cool.service.authentication.GCHeaderAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
}
Other than that, the rest of the configuration is correct.
Related
How do I define basic authentication using Swagger 2.0 annotations and have it display in swagger UI.
In the resource I have:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();
I looked here:
https://github.com/swagger-api/swagger-core/wiki/Annotations#authorization-authorizationscope
And it says "Once you've declared and configured which authorization schemes you support in your API, you can use these annotation to note which authorization scheme is required on a resource or a specific operation" But I can't find anything that talks about where to declare and configure the authorization schemes.
Update:
I found code on how to declare the schema, but I still do not see any information about the authentication schema in the UI. I'm not sure what I am missing
#SwaggerDefinition
public class MyApiDefinition implements ReaderListener {
public static final String BASIC_AUTH_SCHEME = "basicAuth";
#Override
public void beforeScan(Reader reader, Swagger swagger) {
}
#Override
public void afterScan(Reader reader, Swagger swagger) {
BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
}
}
Using Springfox 2.6 annotations, you must first define Basic authentication as one of the security schemes when you set up the Docket in your configuration, like this:
List<SecurityScheme> schemeList = new ArrayList<>();
schemeList.add(new BasicAuth("basicAuth"));
return new
Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo)
.securitySchemes(schemeList)
...
Then you can use the Springfox annotations in your service to set Basic Auth for the operation for which you want to require authentication:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();
I struggeled with this as well. In my case i used the swagger-maven-plugin. To solve this i added this within the maven plugin:
<securityDefinitions>
<securityDefinition>
<name>basicAuth</name>
<type>basic</type>
</securityDefinition>
</securityDefinitions>
After that i was able to add it on my resource like this:
#Api(value = "My REST Interface", authorizations = {#Authorization(value="basicAuth")})
The generated json included the security element for each endpoint:
"security":[{
"basicAuth" : []
}]
And the security definition:
"securityDefinitions" : {
"basicAuth" : {
"type" : "basic"
}
}
I hope this helps others as well.
You can use the #SwaggerDefinition
http://swagger.io/customizing-your-auto-generated-swagger-definitions-in-1-5-x/
or you can configure the swagger object directly, here's an example
http://www.programcreek.com/java-api-examples/index.php?source_dir=rakam-master/rakam/src/main/java/org/rakam/WebServiceRecipe.java
Is there a way I can restrict access to /monitoring url generated by Java-Melody plugin in Grails using Shiro roles?
Update: a little bit more details. It's no problem so secure most Grails ressources with shiro. But in case of the java melody plugin, it seems that the melody filter is executed before the shiro filter gets executed. This renders shiro useless.
There are some solutions which say that this might be fixed through a change in the web.xml, but this is not a quick hit and I (rdmueller) didn't manage to make it work yet. The web.xml plugin also seems to promise some help, but I don't want to add another plugin just to secure one plugin.
Some older statements found on the web state that this problem should be already solved through the usage of the loadAfter list in this file: https://github.com/javamelody/grails-melody-plugin/blob/master/GrailsMelodyGrailsPlugin.groovy - but it seems that this only worked for older versions of Grails.
Update2: In order to make it easier to propose a solution, I've create a Grails 2.2.4 sample: https://github.com/rdmueller/SO30739581
just clone the project, do a grailsw run-app and navigate to
http://localhost:8080/SO30739581/dbdoc
and you'll get a login screen via shiro. Navigate to
http://localhost:8080/SO30739581/monitoring
and you'll get the melody screen without being logged in :-(
I ended up doing so by making changes to web.xml for HTTP authentication. Add this to you web.config file.
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Monitoring</realm-name>
</login-config>
<security-role>
<role-name>monitoring</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Monitoring</web-resource-name>
<url-pattern>/monitoring</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>monitoring</role-name>
</auth-constraint>
</security-constraint>
Then add a user and role to your tomcat-users.xml
<user username="yourusername" password="yourpassword" roles="monitoring"/>
I assume you're using Grails 2.x, you could hardcode it this way :
<!-- language: java-->
// grails-app/conf/MonitoringFilters.groovy
import org.apache.shiro.SecurityUtils
class MonitoringFilters {
def dependsOn = [ShiroSecurityFilters]
def filters = {
myMonitoringArea(uri: "/monitoring") {
before = {
SecurityUtils.subject.hasRole('ADMIN')
}
}
}
}
This is not a "quick hit", but the following approach should work with Shiro or whatever security framework your Grails app uses.
In web.xml, add the following elements above any existing <filter> elements:
<filter>
<filter-name>melodyFilter</filter-name>
<filter-class>com.your.package.MelodyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>melodyFilter</filter-name>
<url-pattern>/monitoring/*</url-pattern>
</filter-mapping>
This will call com.your.package.MelodyFilter any time the /monitoring/* url pattern is invoked.
Next, you'll need to create a MelodyFilter Java class in /src/java/com/your/package/MelodyFilter.java.
In the body of the doFilter method, you may call a Grails service method to perform any desired security checks, as follows:
package com.your.package;
import com.my.grails.app.MyService;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class MelodyFilter implements Filter {
#Override
public void destroy() { }
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String uri = ((HttpServletRequest)request).getRequestURI();
HttpSession session = ((HttpServletRequest)request).getSession(false);
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
// replace MyService with your actual service
MyService myService = (MyService)ctx.getBean("myService");
// replace isUserAuthorized with your actual service method;
// session and uri params included to demonstrate how to pass them
// your argument list can be whatever your service method requires
boolean authorized = myService.isUserAuthorized(session, uri);
if (authorized) { chain.doFilter(request,response); }
else {
request.setAttribute("error", "User is not authorized to access " + uri);
request.getRequestDispatcher("/someController/someAction").forward(request, response);
}
}
#Override
public void init(FilterConfig filterConfig) throws ServletException { }
}
Then simply implement myService.isUserAuthorized() to perform whatever security checks you desire.
I have verified this technique works in Grails-2.3.6 with grails-melody:1.59.0
Just to list all available options:
the shiro-protect-any - plugin seems to work, but IMHO, it seems to be to be a bit too complicated and the plugin is "not fully tested" (says the author)...
I am trying to get further into grails3 and I am unsure about plugin descriptor and doWithWebDescriptor:
src/main/groovy/grails/plugin/plugin/PluginGrailsPlugin.groovy
def doWithWebDescriptor = { xml ->
def listenerNode = xml.'listener'
listenerNode[listenerNode.size() - 1] + {
listener {
'listener-class'(someClass.name)
}
}
}
I tried grails install-templates under grails 3 and no web.xml was generated... I also had a look at the default generated plugin descriptor which did not appear to have doWithWebDescriptor...
Was wondering if this has changed - is it no longer producing a web.xml or if it is what should I be doing to register a listener under grails 3 .
I have managed to get default tomcat websocket listener to work via a spring boot grails app:
It is documented here:
https://github.com/vahidhedayati/testwebsocket-grails3
I have decided to update this post and include all my findings so far on this matter.
More specifically the application.groovy inside your application grails-app/init folder:
This bean initiates default tomcat websocket listener:
#Bean
public ServletListenerRegistrationBean<AnotherWebSocketHandler> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<AnotherWebSocketHandler>(new AnotherWebSocketHandler());
}
Whilst messing around to reuse in plugin, the findings are:
The above project is a basic grails application which does 2 things, a basic spring socket as well java 1.X Websocket:
Here is how to use Default websocket in a grails 3 plugin
In you plugin descriptor you have something like this:
Closure doWithSpring() {
{->
wsChatConfig DefaultWsChatConfig
}
}
In this plugin I have left both methods of initiating the listener:
#Bean
public ServletContextInitializer myInitializer() {
return new ServletContextInitializer() {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(WsCamEndpoint)
servletContext.addListener(WsChatFileEndpoint)
}
}
}
// Alternative way
#Bean
public ServletListenerRegistrationBean<WsChatEndpoint> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<WsChatEndpoint>(new WsChatEndpoint())
}
The top method came in very handy since you can only initialise 1 ServletListenerRegistrationBean and I had to resort to the top method to enable other listeners... I could have just used the top primary for all the calls. Left in for future reference..
With this in place, spring boot now emulates the same as web.xml would when registering a listener. The actual groovy classes that load the websockets from there are as they were i.e. using default websocket calls such as onOpen onMessage etc..
From Grails 3 there's a new way of adding runtime configuration using spring registration beans in the Plugin method doWithSpring. doWithWebDescriptor is not used anymore.
This should work for the Servlet Listeners:
Closure doWithSpring() {{ ->
MyListener(ServletListenerRegistrationBean) {
listener = bean(someClass)
order = Ordered.HIGHEST_PRECEDENCE
}
}}
Disclaimer: I didn't test this code.
Refer to the Gails documentation.
I'm trying to configure a Grails app in a pre-authenticated scenario, using Spring Security Core.
So I wrote a custom authentication filter:
class MyAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
protected getPreAuthenticatedPrincipal(request) { "my_username" }
protected getPreAuthenticatedCredentials(request) { "N/A" }
}
added it to Spring:
beans = {
myAuthenticationFilter(MyAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
checkForPrincipalChanges = true
}
}
and registered it in BootStrap, with position PRE_AUTH_FILTER:
class BootStrap {
def init = { servletContext ->
SpringSecurityUtils.clientRegisterFilter('myAuthenticationFilter',
SecurityFilterPosition.PRE_AUTH_FILTER.order)
}
}
Config.groovy only has the standard User, Role, and UserRole class names, plus some staticRules.
Inside the filter, I tried returning all sorts of things from its getPreAuthenticatedPrincipal() method: the user id, the user id as a string, its username, the User object itself… I can see that my filter is being called for each request (which is what I want, having set checkForPrincipalChanges = true) no matter what I return from it, the current user remains anonymous: springSecurityService.principal is still __grails.anonymous.user__
What do I need to change in my setup, to be able to authenticate my users, with their existing groups and roles? I don't want to write an additional authentication provider, I'm fine with Grails's standard daoAuthenticationProvider. Do I need to return something specific from my filter? Do I need to setup some other Spring classes?
I solved it. I'm documenting it here in case somebody else needs to do the same.
Basically the missing piece was to configure a new PreAuthenticatedAuthenticationProvider as the only provider. No additional code needed, just define it in resources:
myAuthenticationProvider(PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('authenticationUserDetailsService')
}
and set it as the only provider in Config:
grails.plugin.pringsecurity.providerNames = ['myAuthenticationProvider']
Then, from the authentication filter, just return the username of the pre-authenticated user, or null if none (the anonymous user.)
I'm using the spring security (core 2.0-SNAPSHOT and ldap 2.0-RC2) plugins in my Grails 2.4.RC1 project. I'd like to be able to reuse the LdapTemplate that has been configured for use in spring security but I'm not sure how to inject the LdapTemplate into my service class.
Here's my simple service:
#Transactional
class EmployeeSynchronizationService implements EmployeeSynchronizer {
LdapTemplate ldapTemplate
void syncEmployees() {
// do work with ldapTemplate... but ldapTemplate is null
println ldapTemplate
sync(getUsernameToEmployeeMap(), getEmployeeLdapInfo())
}
...
And based on this stackoverflow post, my resources.groovy file looks like this:
beans = {
employeeSynchronizer(employee.EmployeeSynchronizationService) {
ldapTemplate=ref(ldapTemplate)
}
}
However, when I inject the EmployeeSynchronizer into a controller and invoke its syncEmployees method I see that the LdapTemplate is null.
Note: this same question was asked (but not answered) here.