grails/spring security - issue on get all connected users - spring

I followed an article to get all connected users with spring securty in Grails, but it failed at getAllPrincipals method:
"Message: Cannot invoke method getAllPrincipals() on null object"
The code:
resources.groovy
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.core.session.SessionRegistryImpl
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
beans = {
sessionRegistry(SessionRegistryImpl)
sessionAuthenticationStrategy(ConcurrentSessionControlStrategy, sessionRegistry) {
maximumSessions = -1
}
concurrentSessionFilter(ConcurrentSessionFilter){
sessionRegistry = sessionRegistry
expiredUrl = '/login/concurrentSession'
}
}
web.xml
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
controller
def sessionRegistry
def users= new ArrayList<User>(sessionRegistry.getAllPrincipals())
http://classpattern.com/spring-security-sessionregistry-on-grails.html#.U5GICfl_uhF

install templates: grails install-templates
web.xml will be found in : src/templates/war
Be sure that listener tag is before servlet tag :
Get all users :
sessionRegistry.getAllPrincipals().collect{User.get(it.id)}

I found this problem and what my solution is to declare sessionRegistry as variable class for example
class DummyController {
def sessionRegistry
def index() {
def users= new ArrayList<User>(sessionRegistry.getAllPrincipals())
}
}

Related

Unable to create file upload service - Receiving ModelValidationException (No injection source ) during startup [duplicate]

I am using Jersey based restful Service implementation strategy to build a service which will be used to upload files.
My service class name is : UploadFileService.java (See Code below)
package com.jerser.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
#Path("/fileUpload")
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
// save uploaded file to new location
private void writeToFile(InputStream uploadedInputStream,
String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(
uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
These are the JAR files I have inside my lib:
aopalliance-repackaged-2.4.0-b10.jar
asm-debug-all-5.0.2.jar
hk2-api-2.4.0-b10.jar
hk2-locator-2.4.0-b10.jar
hk2-utils-2.4.0-b10.jar
javassist-3.18.1-GA.jar
javax.annotation-api-1.2.jar
javax.inject-2.4.0-b10.jar
javax.servlet-api-3.0.1.jar
javax.ws.rs-api-2.0.1.jar
jaxb-api-2.2.7.jar
jersey-client.jar
jersey-common.jar
jersey-container-servlet-core.jar
jersey-container-servlet.jar
jersey-core-1.11.jar
jersey-guava-2.17.jar
jersey-media-jaxb.jar
jersey-multipart-1.18.jar
jersey-server.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar
persistence-api-1.0.jar
validation-api-1.1.0.Final.jar
I am getting the following error when I am trying to up my tomcat server :
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[multipart/form-data], producedTypes=[], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.jerser.service.UploadFileService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#d3e2d4]}, definitionMethod=public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition), parameters=[Parameter [type=class java.io.InputStream, source=file, defaultValue=null], Parameter [type=class com.sun.jersey.core.header.FormDataContentDisposition, source=file, defaultValue=null]], responseType=class javax.ws.rs.core.Response}, nameBindings=[]}']
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:528)
at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:166)
at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:327)
at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:286)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:324)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:338)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:171)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:363)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1176)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1102)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1009)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4885)
at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5212)
at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5207)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Over the internet I found there are plenty of example which shows How to upload MULTIPART file using RESTFul API. But with same solution. I am not able to run those code as well.
I think I am doing something wrong with the JAR files. Could anyone please help me on this?
Get rid of jersey-multipart-1.18.jar. That is for Jersey 1.x. Add these two
jersey-media-multipart-2.17
mimepull-1.9.3
For Maven you would use the following dependency (you don't need to explicitly add the mimepull dependency, as this one will pull it in).
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.17</version> <!-- Make sure the Jersey version matches
the one you are currently using -->
</dependency>
Then you need to register the MultiPartFeature. If you are using a ResourceConfig for configuration, you can simply do
register(MultiPartFeature.class);
If you are using web.xml, then you can add the class as an <init-param> to the Jersey servlet
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
Note that if you have multiple providers that you want to register, then you can delimit each provider class with a comma, semicolon, or space/newline. You cannot use this same param-name twice. See Suarabh's answer
UPDATE
Also, once you get rid of jersey-multipart-1.18.jar you will have compile errors for the missing imported classes. For the most part, the class names are still the same, just the packages have changed, i.e.
org.glassfish.jersey.media.multipart.FormDataParam
org.glassfish.jersey.media.multipart.FormDataContentDisposition
For Dropwizard
If you're using Dropwizard, instead of adding the jersey-media-multipart, they document for your to add dropwizard-forms instead. And instead of registering the MultiPartFeature, you should register the MultiPartBundle
#Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
bootstrap.addBundle(new MultiPartBundle());
}
Really doesn't make much difference though as all the Dropwizard bundle does is register the MultiPartFeature with the ResourceConfig.
Aside
If you are here for a different ModelValidationException, here are some links for information on other causes of the exception.
1
2
3
Yet another possible cause for this very generic error is that Jersey only searches for factories associated with the last annotation when multiple ones are declared on a param. (See bug report)
Until this is fixed, if you are using any other annotations besides #FormDataParam, it has to come last.
This works:
#NotEmpty #FormDataParam("myParam") String myParam
This does not:
#FormDataParam("myParam") #NotEmpty String myParam
I too got the same exception.I did the following changes in web.xml
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.moxy.json.MoxyFeature;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
and changed jersey 2.7 to 2.9 .I do not know what change of this 2 has solved the issue.
Register MultiPartFeature.
In web.xml add to the Jersey servlet:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
Below code worked for me:
Class ->>> add it
Class Property --->> add it
Public Class userREST () {
#POST
#Path("upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response uploadImageFile(#FormDataParam("uploadFile") InputStream fileInputStream,
#FormDataParam("uploadFile") FormDataContentDisposition fileFormDataContentDisposition,
#FormDataParam("FIR_REG_NUM") String FIR_REG_NUM, #FormDataParam("LOGIN_ID") String LOGIN_ID) {
final_json_result = WriteFileInFolder.fileAnalysis(fileInputStream, fileFormDataContentDisposition, FIR_REG_NUM,
LOGIN_ID);
return Response.ok(final_json_result).build();
}// uploadImageFile
Public Class FileJAXRSConfig () {
package ####.jaxrs.jwt;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import ####.helper.Common###;
import ####.jaxrs.jwt.filters.JWTRequestFilter;
import ####.jaxrs.jwt.filters.JWTResponseFilter;
import ####.service.FileServicesREST;
#ApplicationPath("fileservice")
public class FileJAXRSConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Common###.logging("#ApplicationPath#FileServicesREST...");
Set<Class<?>> clazzes = new HashSet<Class<?>>();
clazzes.add(JWTRequestFilter.class);
clazzes.add(FileServicesREST.class);
clazzes.add(JWTResponseFilter.class);
return clazzes;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("jersey.config.server.provider.packages", "####.service");
properties.put("jersey.config.server.provider.classnames", "org.glassfish.jersey.media.multipart.MultiPartFeature");
return properties;
}
}
Don't need to add following in web.xml
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>mha.###.service</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
If someone is using #FormDataParam with #ApiOperation swagger annotation, it won't work(as per swagger latest version at this time) as mentioned here:
https://github.com/swagger-api/swagger-ui/issues/169
I had this same problem with Scala and this helped me solve it. Just want to add some Scala specific details to help anyone using Dropwizard with Scala. Here is an example of how to "register" the MultiPartFeature in a Scala and Dropwizard project.
package org.research.s3.service
import io.dropwizard.Application
import io.dropwizard.setup.Environment
import org.research.s3.service.resource._
import org.research.service.s3.resource.UploadResource
import org.glassfish.jersey.media.multipart.{FormDataParam,MultiPartFeature}
class CmdaaApp() extends Application[CmdaaAppConfig] {
override def run(t: CmdaaAppConfig, env: Environment): Unit = {
env.jersey().register(new RootResource)
//Need this to make the file upload code work in
env.jersey().register(new MultiPartFeature)
env.jersey().register(new UploadResource(curBucket))
}
}
object CmdaaApp {
def main(args: Array[String]): Unit = new CmdaaApp().run(args: _*)
}
and here is the code for the UploadResource that does the upload:
package org.research.service.s3.resource
import java.io.{FileInputStream, InputStream}
import com.google.gson.{Gson, GsonBuilder}
import javax.ws.rs.core.MediaType.APPLICATION_JSON
import javax.ws.rs._
import javax.ws.rs.core.Response
import javax.ws.rs.core.MediaType
import org.research.util.OptionSerializer
import org.research.s3.service.resource.s3Bucket
import org.glassfish.jersey.media.multipart.{FormDataParam,MultiPartFeature}
#Path("/file")
class UploadResource(currentBucket: s3Bucket) {
val gsonb = new GsonBuilder()
gsonb.registerTypeAdapter(classOf[Option[Any]], new OptionSerializer)
val gson = gsonb.create
#POST
#Path("upload")
#Produces(Array(APPLICATION_JSON))
#Consumes(Array(MediaType.MULTIPART_FORM_DATA))
// def uploadFile(): Response = {
def uploadFile(#FormDataParam("file") uploadedInputStream: InputStream): Response = {
/* Need code here to get a uuid for the file name
Then return the uuid if we have success and of course 200
*/
Response.ok.entity(currentBucket.upload("testName",uploadedInputStream,false)).build()
//Response.ok().build()
}
}
This code refers to an s3 bucket but you don't need that. You can just replace that call with code do download your incoming file data to a regular file.
scala
I had the same problem when I tried to upload the file.
I spent a lot of time until I found a solution to the problem.
1.If you changed version of your JARs files you may have a version conflicts!
Clean up your artifacts/libs and rebuild project.
2.You need to register your UploadFileService class too:
register(MultiPartFeature.class);
register(UploadFileService.class);
Hope it will help someone and save your time.
in case you are getting this error while writing Dropwizard tests for the upload Resource this is the solution:
add dependency on dropwizard-forms
2.add this in the application file:
#Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
bootstrap.addBundle(new MultiPartBundle());
}
in the test file add:
ResourceExtension.builder()
.addResource(new FileResource())
.addProvider(new MultiPartFeature())
.build();
I had a very similar problem and the answer that helped me was this https://stackoverflow.com/a/30407999/6801721
I was trying to use a user defined object as a query parameter and from the answer that's usually not allowed unless it meets some conditions.
In case someone comes across this in the future and is running into the same problem I was running into. Make sure that the annotations you are importing are from the correct packages. In my case I was importing javax.websocket.server.PathParam instead of javax.ws.rs.PathParam.

using shiro with stormpath for jax-rs rbac

I'm attempting to adapt this excellent stormpath post by Brian Demers - https://stormpath.com/blog/protecting-jax-rs-resources-rbac-apache-shiro - to my own purposes and so far it works pretty well - except that now I want to add stormpath for user/role management rather then having the users in a shiro-ini file.
I'm using Apache Shiro shiro-jaxrs 1.4.0-RC to secure a REST endpoint using jax-rs. It works fine. I'm able to selectively secure the endpoints using a #RequiresPermissions tag like so:
#Path("/scan")
#Produces("application/json")
public class ScanService {
final static Logger logger = Logger.getLogger(ScanService.class);
#GET
#Path("/gettest")
#RequiresPermissions("troopers:read")
public List<Barcode> gettest() throws Exception {
ArrayList<Barcode> listofstrings = new ArrayList<Barcode>();
Barcode b = new Barcode();
b.setBarcode("this is a big barcode");
listofstrings.add(b );
return listofstrings;
}
#GET
#Produces( MediaType.APPLICATION_JSON )
#Path("/gettest2")
public List<Barcode> gettest2() throws Exception {
ArrayList<Barcode> listofstrings = new ArrayList<Barcode>();
Barcode b = new Barcode();
b.setBarcode("this is a BIGGER barcode");
listofstrings.add(b );
return listofstrings;
}
I also have an application class to add my resource and the ShiroFeature class like so:
package ca.odell.erbscan;
import ca.odell.erbscan.ws.ScanService;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.web.jaxrs.ShiroFeature;
import com.stormpath.shiro.jaxrs.StormpathShiroFeature;
#ApplicationPath("/")
public class ERBApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
// register Shiro
classes.add( ShiroFeature.class);
// register resources
classes.add(ScanService.class);
return classes;
}
}
and my web.xml to init my Application class like so:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ERBSCAN</display-name>
<servlet>
<servlet-name>ERBRest</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>ca.odell.erbscan</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>ca.odell.erbscan.ERBApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ERBRest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
</web-app>
and finally my shiro.ini
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
[urls]
/** = noSessionCreation, authcBasic[permissive]
[users]
# format: username = password, role1, role2, ..., roleN
root = secret,admin
emperor = secret,admin
officer = secret,officer
guest = secret
[roles]
admin = *
officer = troopers:create, troopers:read, troopers:update
What I want to do next is add Stormpath for RBAC rather then having users and roles in a file. My feeling is there's a simple way to do this and that I'm overthinking it.
I thought it would be a fairly straightforward manner of adding in my shiro.ini:
stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.cacheManager = $cacheManager
stormpath.application.href=http://....
But I was wrong. Could someone point me in the right direction?
thanks for reading that post!
A couple things I want to point out:
Use this feature com.stormpath.shiro.jaxrs.StormpathShiroFeature
instead of ShiroFeature
Your shiro.ini could look something like:
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
[urls]
/** = noSessionCreation, authcBasic[permissive]
[stormpath]
stormpath.application.href=http://....
Permissions can be stored as user or role Custom Data, you can update the Custom Data in the Stormpath admin console:
{
… your other custom data fields …,
"apacheShiroPermissions": [
"troopers:create",
"troopers:read",
"troopers:update"
]
}
This blog post covers the custom data bit, it is a little older, but still relevant. I'll be updating the doc on this in the near future, so feedback welcome.
If this doesn't help you can also ping support, and we will get you going!
I'm going to answer my own question here. I don't think this is the best solution, but it something I managed to get to work.
I followed this web app tutorial off of the shiro site.
https://shiro.apache.org/webapp-tutorial.html
I checked out step6 of the project and copied the [main] section of the shiro.ini as follows: Note I added the
https://api.stormpath.com/v1/applications/$STORMPATH_APPLICATION_ID
at the bottom the [main] section.
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.cacheManager = $cacheManager
# we can disable session tracking completely, and have Stormpath manage it for us.
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
securityManager.sessionManager.sessionIdUrlRewritingEnabled = false
stormpathRealm = com.stormpath.shiro.realm.ApplicationRealm
stormpathRealm.client = $stormpathClient
stormpathRealm.groupRoleResolver.modeNames = name
securityManager.realm = $stormpathRealm
stormpathRealm.applicationRestUrl = https://api.stormpath.com/v1/applications/$STORMPATH_APPLICATION_ID
I then completely removed the [users] section of the shiro.ini. Since it's now wired up to Stormpath, I need to add users and groups there. My ScanService ( as above ) has a method called gettest decorated thusly:
#GET
#Path("/gettest")
#RequiresPermissions("trooper:read")
public List<Barcode> gettest() throws Exception {
.
.
.
so I need to added an account, a group and permissions in stormpath to match the permissions on the above resource. In order to do this, I need to add an account in Stormpath ( I already have the Application setup ) under my existing test application. I also added a group called officer1. The under this group I added Custom Data an array called apacheShiroPermissions - I added a string key/value pair 'trooper:read' to the apacheShiroPermissions - the JSON is below
{
"apacheShiroPermissions": [
"trooper:read"
]
}
Then I simply made sure my account - in this case jlpicard was part of the officer1 group.
Testing with curl
curl --user jlpicard:Changeme1 http://localhost:8080/JPA1_Web_exploded/rest/scan/gettest
Confirms jlpicard has access on the permission level. Adding and removing the strings entry's to the apacheShiroPermission array i.e. allows that fine grained access.
Also removing jlpicard from the officer1 or adding another account to it works as expected.
There is undoubtedly a better way to do this but this has what was worked for me so far.

Running cucumber-groovy features against a spring boot api

I've been attempting to get cucumber-groovy working with spring-boot, but it's not been going well. I get the error org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8080/applicants": Connection refused; nested exception is java.net.ConnectException: Connection refused which seems to indicate that it's hitting the endpoint, but that the service isn't running.
I've read that I need to have a cucumber.xml file, but my project is not using any xml config, it's all annotations, so instead I've got this:
package support
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "com.base.package")
public class CucumberConfiguration {}
I've added it to the World, but this seems to be the wrong way of doing things (i.e. I don't know how to add an annotation on groovy step defs).
package support
import com.thing.app.Application
import org.junit.runner.RunWith
import org.springframework.boot.test.SpringApplicationContextLoader
import org.springframework.boot.test.WebIntegrationTest
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
import org.springframework.test.context.web.WebAppConfiguration
import static cucumber.api.groovy.Hooks.*
//#RunWith(SpringJUnit4ClassRunner)
//#ContextConfiguration(classes = Application, loader = SpringApplicationContextLoader)
//#WebAppConfiguration
//#WebIntegrationTest
#ContextConfiguration(classes = CucumberConfiguration)
public class AbstractTest {
}
World() {
new AbstractTest()
}
Before() {}
After() {}
I left in my other annotations to kind of show what I've done so far. None of it has worked.
I've also tried setting up an AbstractDefs class as seen here https://github.com/jakehschwartz/spring-boot-cucumber-example/tree/master/src/test/java/demo, but that also hasn't worked, mostly because I'm not using the cucumber-java style of things, but instead the cucumber-groovy style, which doesn't use step definition classes.
Edit: Just discovered I was doing things wrong by having an env.groovy, I'm used to the ruby cucumber, so I'm having trouble finding all the little problems. Still am having the same issue though, I don't know how to execute in a Spring context.
You can instantiate Spring test context with io.cucumber.spring.SpringFactory and register adapter in World to allow groovy script has access to Spring beans:
env.groovy:
#ContextConfiguration(classes = TestConfiguration, loader = SpringBootContextLoader)
class CucumberContextConfiguration {
}
//adapter bypassing World properties to Spring context
class SpringFactoryWorldAdapter {
private final SpringFactory factory;
SpringFactoryWorldAdapter(SpringFactory factory) {
this.factory = factory;
}
#Override
Object getProperty(String s) {
return factory.testContextManager.getContext().getBean(s);
}
}
def factory; //Keep state to prevent repeated context initialization
World { args ->
if (factory == null) {
factory = new SpringFactory()
factory.addClass(CucumberContextConfiguration)
factory.start()
}
new SpringFactoryWorldAdapter(factory)
}

Getting the number of currently logged in users from spring security core plugin in grails

I'm trying to get the number of currently logged in grails application. I'm using:
Grails 2.3.1 and spring-security-core:2.0-RC2 plugin.
By refering to this thread:
GRAILS: how to get the number of currently signed in users via spring security core plugin?
resources.groovy
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy
beans = {
sessionRegistry(org.springframework.security.core.session.SessionRegistryImpl)
concurrencyFilter(org.springframework.security.web.session.ConcurrentSessionFilter){
sessionRegistry = sessionRegistry
expiredUrl = '/login/concurrentSession'
}
sessionAuthenticationStrategy(ConcurrentSessionControlStrategy, sessionRegistry) {
maximumSessions = -1
}
}
I also modified web.xml and added:
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
These are the only changes that I made to my application.
Modifying BootStrap in such fashion
class BootStrap {
def springSecurityService
def authenticationManager
def concurrentSessionController
def securityContextPersistenceFilter
def init = { servletContext ->
authenticationManager.sessionController = concurrentSessionController
}
def destroy = {
}
}
Causes error on start-up:
Error initializing the application: No such property: sessionController for class: org.springframework.security.authentication.ProviderManager
Message: No such property: sessionController for class: org.springframework.security.authentication.ProviderManager
The only think that I accomplished so far is that SessionRegistry is injected to my controller and I'm able to invoke
sessionRegistry.getAllPrincipals().size()
without getting NullPointerException but it returns 0 no matter how many users are currently logged in.
I don't know where to proceed from here since I'm a beginner with spring.

Integrating spring and vaadin

Is it good to integrate Spring and vaadin? I am looking to use vaadin in view layer and spring for my services. So far I am not able to find any neat solution for integration. Is it even a good idea for Production applications like management solutions or ERP?
what could be the design of the application?
How to keep clear separation between application layers?
Issues with Vaadin integration with spring security?
How to manage scope of spring beans?
Also could anyone share the advantages and disadvantages of this integration over spring MVC.
You have a very useful add-on for Vaadin called SpringVaadinIntegration.
You can keep a clean separation very easily with Vaadin, just use Spring #Autowired and services for the data retrieval and modification.
I've used Spring security and I had no problems with Vaadin.
You can manage the scope with the #Scope annotation, with three differents values, if I remember correctly: Singleton (default), Prototype and Session.
Did you consider using Vaadin UIProvider mechanism. This way autowiring in UI is totally transparent.
You can have a look at a really simple example that uses this solution on github: spring-vaadin-example
You don't need any special vaadin addons for spring at all. Just use aspectj and #Configurable annotation along with #Autowired for every component you want to integrate with spring. Like this:
#Configurable(preConstruction = true)
public class LoginUserPasswdDialog extends LoginDialogBase {
static final Logger log = Logger.getLogger(LoginUserPasswdDialog.class);
#Autowired
private AppConfig config;
#Autowired
UserFactory userFactory;
StringBuffer name;
LoggedAction action;
protected Window parent = null;
protected Button ok;
protected Label l;
protected TextField nameText;
protected PasswordField password;
protected CheckBox saveUserPass;
protected final Window w = new Window("");
#SuppressWarnings("serial")
public void create(AbstractComponent component) throws Exception {
parent = component.getWindow();
VerticalLayout v = new VerticalLayout();
v.setSizeFull();
v.setSpacing(true);
l = new Label(
_.getString("LoginUserPasswdDialog.0"), Label.CONTENT_XHTML); //$NON-NLS-1$
l.setSizeFull();
l.addStyleName("centeredLabel");
v.addComponent(l);
HorizontalLayout h = new HorizontalLayout();
h.setMargin(true);
h.setSpacing(true);
nameText = new TextField();
nameText.setWidth("100%");
v.addComponent(nameText);
nameText.focus();
password = new PasswordField();
password.setWidth("100%");
v.addComponent(password);
saveUserPass = new CheckBox(_.getString("LoginUserPasswdDialog.1")); //$NON-NLS-1$
v.addComponent(saveUserPass);
v.setComponentAlignment(saveUserPass, Alignment.MIDDLE_RIGHT);
ok = new Button(_.getString("LoginUserPasswdDialog.2")); //$NON-NLS-1$
ok.setWidth("100px");
ok.setClickShortcut(KeyCode.ENTER);
h.addComponent(ok);
h.setComponentAlignment(ok, Alignment.MIDDLE_CENTER);
v.addComponent(h);
v.setComponentAlignment(h, Alignment.MIDDLE_CENTER);
Cookie nameCookie = CookieUtils.getCookie("username");
Cookie passCookie = CookieUtils.getCookie("password");
if (nameCookie != null && passCookie != null) {
nameText.setValue(nameCookie.getValue());
password.setValue(passCookie.getValue());
saveUserPass.setValue(true);
}
w.setWidth("400px");
w.setCaption(config.getTitle() + _.getString("LoginUserPasswdDialog.4"));
w.setResizable(false);
w.setClosable(false);
w.setModal(true);
w.center();
ok.addListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
String name = (String) nameText.getValue();
String pass = (String) password.getValue();
User u = userFactory.getUser(name, pass);
if (u != null) {
if ((Boolean) saveUserPass.getValue()) {
CookieUtils.makeCookie("username", name);
CookieUtils.makeCookie("password", pass);
} else {
CookieUtils.deleteCookie("username");
CookieUtils.deleteCookie("password");
}
userFactory.updateUser(u);
action.loggedIn(u);
parent.removeWindow(w);
return;
} else {
password.setValue("");
WaresystemsUI.handle
.get()
.getMainWindow()
.showNotification(
"",
_.getString("LoginUserPasswdDialog.3"), Notification.TYPE_ERROR_MESSAGE); //$NON-NLS-1$
return;
}
}
});
w.addComponent(v);
parent.addWindow(w);
}
#Override
public void setAction(LoggedAction loggedAction) {
this.action = loggedAction;
}
}
Of course you need add support to the web.xml:
<!-- SPRING -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
<init-param>
<param-name>threadContextInheritable</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Take a look also on Spring UI scope add-on http://vaadin.com/addon/spring-ui-scope
The add-on defines custom Spring scope: UI-scope, which pass well with Vaadin application.
There is also sample application using the scope.

Resources