Upcoming version 3

2,846 views
Skip to first unread message

Jorge Aliss

unread,
May 7, 2014, 12:12:21 AM5/7/14
to secure...@googlegroups.com
Hi All,

I just pushed into master what is going to become version 3 of SecureSocial.  These changes are meant to fix the pain points that many are experiencing. It’s still a draft but I think it’s good enough to share.  Due to the nature of the changes it was impossible to maintain backwards compatibility but I think upgrading will be worth the effort.  

Here’s a summary of the main changes:

1) Async support
All the module should be async now. I refactored all the places where blocking calls were being made.

2) Managed Controllers
All controllers are no longer objects but rather traits that you can extend.  You will see all of them come in pairs, e.g.: BaseLoginPage and LoginPage.  The first is a trait that implements the functionality and the second a class that implements it. The implementing class is then referenced from the module routes file.

3) Removed RoutesHelper
Having managed controllers allowed me to remove the RoutesHelper that was causing compilation problems when custom routes were used.  Now you can just add/remove routes to enable/disable the functionality you need and you should not get compilation errors.  There is now a RoutesService that needs to be customized for some pages when you do not use the default routes.  

4) Routes file
The module has a default routes file that you can include in your app using something like:

# your app routes
GET / myController.index

-> auth    securesocial.Routes

That will include all the routes, if you want a subset of the routes or change the paths just add the routes manually.

5) Dependency Injection support
Since all controllers are managed you can now extend them and add any dependency either in the code itself or by using your preferred DI framework.

6) Plugins
Using plugins was causing some problems and I decided to make them regular classes.  

7) Services
I turned some helper classes and objects into services: a trait defines the interface and a default implementation is provided with the original code.  For example things like:
    -  HttpService that allows you to make http calls. The default implementation uses the WS class from Play.
    -  CacheService: The default implementation uses the Play cache
    -  AvatarService: A trait to get avatars from external services. The default implementation is using Gravatar.

8) RuntimeEnvironment
I added the concept of a RuntimeEnvironment.  This class holds references to all the services and classes the module needs to work properly.  Think of it as a replacement of the play.plugins file.  

A nice side effect of having this is that you can define different environments for parts of your app. Eg: an admin module can use a its own UserService or a different set of providers. 

Each controller needs an instance of this class so it is now required to implement the getControllerInstance in Global. The sample apps have a basic code that check if a controller that is about to be instantiated needs it and invoke the constructor with the sample RuntimeEnvironment implementation.  You can decide how to pass the environment, either using reflection as in the samples, using a DI framework or extending the controller and overriding the env attribute and hardcoding a reference to your environment.

9)  Renamed Identity to BasicProfile
A BasicProfile is the same set of data that the Identity trait used to hold.  The module creates a BasicProfile when an authentication is successful and passes the instance to your app, you can then return an instance of your own object and use it in the actions.  

All the object copying that was using the SocialUser class is gone. I refactored the providers a bit so that is not needed anymore. 

10) Custom user model support
The module allows you to use your own class for the user object now.  There’s no need to implement a trait or extend anything.  So if you had something like:

def myAction = SecuredAction { implicit request =>
    request.user match {
           case u: MyUser => // do something
          case _=> // handle error
   }
}

You can just simplify it to using request.user and forget about the ugly match.  

Using a custom user model is optional, the idea is that if a BasicProfile is good enough for your app you can just use that. The default controllers (not their base traits) use a RuntimeEnvironment that handles BasicProfile, e.g.: RuntimeEnvironment[BasicProfile].

11) Authenticator, AuthenticatorBuilder and AuthenticatorService
Authenticators can now be extended and customized.  The module comes with two implementations: CookieBasedAuthenticator and HttpHeaderAuthenticator.  In theory you can now create an authenticator that stores anything on the client side. This can be used to serialize all the user information so that invocations to SecuredActions do not need to look up the user in the database.  

The new implementation lets you use different Authenticator implementations to protect the actions, this means the same action can be invoked by a client using cookies and an http header.

12) SecuredAction
Some pointed out the need to use content negotiation in their secured apps instead of the ajaxCall flag so I decided to remove it.  

Also, the not authenticated and not authorized responses can be overridden (in the Scala API). I had issues trying to accomplish the same on the Java API (in fact, I bumped into several problems with Java) that I’ll try to fix, the Java side works but it needs some improvements.

13) Testing
Having the services layer should make it easier to test apps as the services can be mocked more easily. Eg: mocking an authenticator to just return a user.

14) Single Page Apps and Mobile support
Having the HttpHeader based authenticator allows for easier integration with SPA and mobile apps.  I added a LoginApi controller that lets you authenticate a user using an API.  It supports the UsernamePasswordProvider and all the OAuth2Providers.

In the case of the UsernamePasswordProvider you can post the user credentials and if they’re ok you will get a json with a token that can be used in an X-Auth-Token header to invoke SecuredActions.  For example:

curl --data "username=so...@email.com&password=some_password” http://localhost:9000/auth/api/authenticate/userpass

For OAuth2 based providers you have to post a JSON with an accessToken generated by the external service (that was obtainer in the client side) along with the user email. The module will the use the accessToken to verify if it works and will compare the email returned by the external service to the one passed in.  If they match then the user is considered to be authenticated.  This is very similar to what the guys at FortyTwo were doing and I thought it would be good to have the functionality built in (http://eng.42go.com/mobile-auth-with-play-and-securesocial/).

For example, having a file test.json with the accessToken and expiresIn values returned after authenticating with Facebook on the client side (e.g.: using Javascript):

{
"email": “so...@email.com”,
"info": {
"accessToken": “an_access_token”,
"expiresIn": a_number_with_expiration_in_seconds
}
}

You can invoke: 

curl -v --header "Content-Type: application/json" --request POST --data-binary "@test.json" http://localhost:9000/auth/api/authenticate/facebook

A sample json response for any of the calls above would be:

{"token":"98b9613dac60890b8e0abf5bc0f77591523df4e6de50b085c832116b8db2cc65511e0de6780f6a49f8755eddabbd46e6afada92160758fd6d4bbb25dc57e0f7b1e4b5b59fbbe543cf80ad1b6d91de7764e3ac1aaa0afac0c312a47bf27258f455606c6c19b1a3d40f8631ce98e6b76e128dddcb29511eb81200ffe9de95cba7a","expiresOn":"2014-05-07T07:43:10.987-03:00"}

You can then invoke a secured action as:

curl -v --header "Content-Type: application/json" -H "X-Auth-Token: 819a9cb9227d2c82af9c1ee2a62b9e7d35725e235e086ab95ecce0b509f3f7b389f430e217e341306ecaebfd1972ac083de73a32341a26f97150ae71fb0417f0031534d818356b2266ffc100e5ee6a50bd1f9ec76b0f68d2ff8ce4d196b4a86b61e002b29b00532ef166cb2eb8476d3ae008c112891628bc0f444c7512c01345" http://localhost:9000/my-protected-action 


There are a lot of other minor changes but this covers the main points.  The documentation has not been updated yet, so use the sample apps as a guide and take a look at the source code :) I wanted to share what I have so far to get feedback and adjust things in preparation for a version 3.   


Thanks to all of you who sent their feedback - either positive or negative - since it influenced and helped improve SecureSocial.
Let me know what you think,

Jorge

Christian Kaps

unread,
May 7, 2014, 3:39:16 AM5/7/14
to secure...@googlegroups.com
Hi Jorge,

very sad that you go this way, but I can understand your decision. It's nice to see that the work on Silhouette has influenced the work on Secure Social. Sad that you do not honor this.

I really like the direction Secure Social moves. Due to the decoupled design it is now possible to easily test the complete application. One thing that I miss are the unit tests for the core framework. Otherwise good work!

Regards,
Christian

Justin Long

unread,
May 7, 2014, 6:46:26 PM5/7/14
to secure...@googlegroups.com
Awesome work! We'll be waiting for a final stable version.

In the meantime, can you Maven publish a securesocial-2.2.0 version for Play! 2.2.x users that were relying on master-SNAPSHOT up until this commit? I noticed SecureSocial was relatively stable in that time, and I'd like to be able to pull this into our project conveniently :)

Thanks!

Jorge Aliss

unread,
May 8, 2014, 10:43:46 AM5/8/14
to secure...@googlegroups.com
Justin,

Just published 2.1.x-SNAPSHOT. Try it out and let me know if it works for you.
Thanks,

Jorge

Justin Long

unread,
May 9, 2014, 6:33:24 PM5/9/14
to secure...@googlegroups.com
Confirmed, I just added that dependency and it worked! Thank you very much for pushing it out.

J

Hai Diep Nguyen

unread,
May 11, 2014, 2:02:18 AM5/11/14
to secure...@googlegroups.com
Yah, that 2.1.x-SNAPSHOT saved my life.

I spent last 2 days to update my code base to the new 3.0 but the final result is not so good. I constantly got UnsupportedClassVersionError
java.lang.UnsupportedClassVersionError: securesocial/controllers/routes: Unsupported major.minor version 51.0

But I love the new changes in 3.0

How that we will have stable version and better sample app soon

Thanks & Best Regards,
Diep

r.gru...@gmail.com

unread,
May 12, 2014, 5:07:05 PM5/12/14
to secure...@googlegroups.com
Regarding the new UserService implementation: What are we supposed to return in the find() method?

I've implemented it like this:

1. search the storage (sql db) for a user entity with the passed in "userId"
2. if found, create a BasicProfile() from the data contained in the user entity and return it
3. if not found, return None

The reason i'm asking: So far the workflow works fine (signup, mailToken verification, finishSignup), but when i login after successful signup,
the "SaveMode" is "SignUp" instead of (what i would assume)  "LoggedIn", hence my application tries to persist a new User, which throws
an unique constraint exception from the db backend.

any help would be greatly appreciated!

thanks.


Jorge Aliss

unread,
May 13, 2014, 7:29:12 AM5/13/14
to secure...@googlegroups.com
Hi Christian,

All the comments I received though this forum, the issues/pull requests on GitHub, emails I exchanged with other developers and comments on Twitter were taken into consideration to improve the new version of SecureSocial.  

I have been saying for months that I was aware and working on fixing the pain points of using the module, that is why I did not consider your proposal a viable option. I have nothing against you or your project.  You and anybody is welcome to help.

Glad to know you like the direction SecureSocial is taking.

Best regards,
Jorge

Jorge Aliss

unread,
May 13, 2014, 7:34:08 AM5/13/14
to secure...@googlegroups.com
Hi,

That is weird. Did you do a play clean? Does this happen with your app only or also with the sample apps?

Jorge

Jorge Aliss

unread,
May 13, 2014, 7:38:10 AM5/13/14
to secure...@googlegroups.com
That is how it should be implemented. Have you checked if your method is working properly?  SecureSocial will call your find method and if you return Some it will use the LoggedIn mode or SignUp instead.

Let me know,
Jorge

r.gru...@gmail.com

unread,
May 14, 2014, 4:56:54 AM5/14/14
to secure...@googlegroups.com

I've been using the pattern matching from the examples to check if it's SaveMode.SignUp or SaveMode.LoggedIn - but unfortunately this always evaluated to SaveMode.SignUp. I've changed it to mode.is(SaveMode.LoggedIn), and now it works.

r.gru...@gmail.com

unread,
May 14, 2014, 4:59:53 AM5/14/14
to secure...@googlegroups.com
Should the latest changes be available in the master-SNAPSHOT version?

I've updated my build.sbt to the following:

libraryDependencies ++= Seq(
  jdbc,
  anorm,
  cache,
  "securesocial" %% "securesocial" % "master-SNAPSHOT"
)

resolvers ++= Seq(
  Resolver.url("sbt-plugin-snapshots", new URL("http://repo.scala-sbt.org/scalasbt/sbt-plugin-snapshots/"))(Resolver.ivyStylePatterns)
)

but when i run my app, i'm getting "object RuntimeEnvironment is not a member of package securesocial.core"


is this the right way to use the project as a snapshot dependency?


cheers

-robert

Jason Turim

unread,
May 20, 2014, 9:10:17 AM5/20/14
to secure...@googlegroups.com
I'm having a similar problem mode.is returns true no matter what's passed in.

Here are the debug statements from my test runs:

[debug] application - Using savemode SaveMode.SignUp
[debug] application - SaveMode.LoggedIn
[debug] application - Updating User
[debug] application - Using savemode SaveMode.LoggedIn
[debug] application - SaveMode.LoggedIn
[debug] application - Updating User

Here is the relevant code in UserService.save

     if (mode.is(SaveMode.LoggedIn)) {
         Logger.debug("SaveMode.LoggedIn")
         updateUser(user)(conn)
     } else if (mode.is(SaveMode.SignUp)) {
         Logger.debug("SaveMode.SignUp")
         createUser(user)
     }

Here is the test code that calls into the UserService methods (these are in separate examples):

//testing login
val user = Helpers.await(userService.save(bp.get, SaveMode.LoggedIn), 10, java.util.concurrent.TimeUnit.SECONDS) 
//testing signup
val user = Helpers.await(userService.save(bp, SaveMode.SignUp), 10, java.util.concurrent.TimeUnit.SECONDS)

Am I doing something obviously wrong?

thanks
Jason

Jorge Aliss

unread,
May 21, 2014, 2:51:33 PM5/21/14
to secure...@googlegroups.com
This has just been fixed (thanks @ddispaltro) and master-SNAPSHOT should make it work now.
Thanks,

Jorge

Dan Di Spaltro

unread,
May 22, 2014, 1:48:50 PM5/22/14
to secure...@googlegroups.com
This looks like a mixed compilation error.  Either SecureSocial was compiled on JDK8 or you are switching between 7 and 8 during compilation.

Vít Šesták 'v6ak'

unread,
May 24, 2014, 5:35:10 AM5/24/14
to secure...@googlegroups.com
Major version 51 means JDK 7. You are using Java 6 or older, aren't you?

Regards,
Vít Šesták 'v6ak'

Muhammad Sheraz Siddiqi

unread,
May 27, 2014, 11:11:11 AM5/27/14
to secure...@googlegroups.com
SecureSocial.currentUser() is removed on MASTER.

Any idea what is its alternate on master ?

Jorge Aliss

unread,
May 27, 2014, 11:14:50 AM5/27/14
to Muhammad Sheraz Siddiqi, secure...@googlegroups.com
You can just use the user in the request.

Jorge

Hossein Kazemi

unread,
May 27, 2014, 12:17:43 PM5/27/14
to secure...@googlegroups.com, Muhammad Sheraz Siddiqi
Hi Jorge,
I am trying out the new features.
Was wondering if there is already a SaveMode.PasswordChange() which is taken care of in the doSave. Then why there is a method for ChangePassword in the AuthService then?
And by SaveMode.LoggedIn() you mean already a signedup user? (maybe name is a bit confusing)
Cheers

Hossein Kazemi

unread,
May 27, 2014, 2:53:48 PM5/27/14
to secure...@googlegroups.com
Hi Jorge,
In addition to the question above. I have a major problem with the new version now.
I am using Guice DI in my project and seems securesocial doesn't like it and project blows up. Here is the stackstrace:

play.api.Application$$anon$1: Execution exception[[ConfigurationException: Guice configuration errors:

1) Could not find a suitable constructor in securesocial.core.java.SecureSocial$Secured. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
  at securesocial.core.java.SecureSocial$Secured.class(SecureSocial.java:154)
  while locating securesocial.core.java.SecureSocial$Secured

1 error]]
at play.api.Application$class.handleError(Application.scala:293) ~[play_2.10-2.2.3.jar:2.2.3]
at play.api.DefaultApplication.handleError(Application.scala:399) [play_2.10-2.2.3.jar:2.2.3]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.3.jar:2.2.3]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.3.jar:2.2.3]
at scala.Option.map(Option.scala:145) [scala-library-2.10.3.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrElse(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.3.jar:2.2.3]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrElse(PlayDefaultUpstreamHandler.scala:260) [play_2.10-2.2.3.jar:2.2.3]
at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344) [scala-library-2.10.3.jar:na]
at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) [scala-library-2.10.3.jar:na]
at play.api.libs.iteratee.Execution$$anon$1.execute(Execution.scala:43) [play-iteratees_2.10-2.2.3.jar:2.2.3]
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) [scala-library-2.10.3.jar:na]
at scala.concurrent.Promise$class.complete(Promise.scala:55) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153) [scala-library-2.10.3.jar:na]
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249) [scala-library-2.10.3.jar:na]
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) [scala-library-2.10.3.jar:na]
at play.api.libs.iteratee.Execution$$anon$2.execute(Execution.scala:70) [play-iteratees_2.10-2.2.3.jar:2.2.3]
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) [scala-library-2.10.3.jar:na]
at scala.concurrent.Promise$class.complete(Promise.scala:55) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153) [scala-library-2.10.3.jar:na]
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249) [scala-library-2.10.3.jar:na]
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) [scala-library-2.10.3.jar:na]
at play.api.libs.iteratee.Execution$$anon$2.execute(Execution.scala:70) [play-iteratees_2.10-2.2.3.jar:2.2.3]
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) [scala-library-2.10.3.jar:na]
at scala.concurrent.Promise$class.complete(Promise.scala:55) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153) [scala-library-2.10.3.jar:na]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:23) [scala-library-2.10.3.jar:na]
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:42) [akka-actor_2.10-2.2.0.jar:2.2.0]
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386) [akka-actor_2.10-2.2.0.jar:2.2.0]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [scala-library-2.10.3.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [scala-library-2.10.3.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [scala-library-2.10.3.jar:na]
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) [scala-library-2.10.3.jar:na]
Caused by: com.google.inject.ConfigurationException: Guice configuration errors:

Could you help me with that?

Adam Kuipers

unread,
Jun 2, 2014, 5:35:32 PM6/2/14
to secure...@googlegroups.com
Hi Jorge,

These look like great updates.

I'm currently working on a REST service with token authentication and we've decided to add social login. How stable is master currently and how soon can we expect version 3 to be released?

Also, will user signup be accessible from a mobile or single page application?

Thanks,
Adam 


On Tuesday, May 6, 2014 9:12:21 PM UTC-7, Jorge Aliss wrote:

Shawn

unread,
Jun 3, 2014, 3:17:29 AM6/3/14
to secure...@googlegroups.com
Thanks Jorge, 

Once again you are working tirelessly on SS which we love. 

Do you know of any examples for testing in the snapshot, I see the test-kit  folder but I am struggling to get my integration tests working and an example would be really helpful. 

Thanks
Shawn

Jorge Aliss

unread,
Jun 3, 2014, 9:09:37 AM6/3/14
to secure...@googlegroups.com
Shawn,

The test-kit which was contributed by Jean Helou was meant to work with the previous version of SecureSocial.   Testing SecureSocial was not that straightforward and he tried to facilitate that. 
The new API in master should make testing easier as things are more modular and can be mocked more easily.  I don't have any examples yet, I need to finish other things and then will tackle that. 

Thanks,
Jorge

Tushar Patel

unread,
Aug 12, 2014, 6:31:57 AM8/12/14
to secure...@googlegroups.com
Hi,

I am having the same problem shown below. The Google Guice returns error while getting constructor instance.

Does anyone has any solution to this?

Thanks.

Tushar Patel

unread,
Aug 12, 2014, 9:02:43 AM8/12/14
to secure...@googlegroups.com
Following are the details of my problem:

public class Global extends GlobalSettings {

    private Injector injector;

           Module UserModule = new AbstractModule() {
            @Override
            protected void configure() {               
                bind( AuthenticationService.class ).to( AuthenticationServiceImpl.class );      
            }
        };

        injector = Guice.createInjector( UserModule );
    }

    @Override
    public <T> T getControllerInstance(Class<T> myClass) {
        return injector.getInstance( myClass );
    }
}


routes file:
GET         /login       @securesocial.controllers.LoginPage.login

build.sbt:
"ws.securesocial" %% "securesocial" % "master-SNAPSHOT"


All my controller methods are non-static as I need to use Guice DI.

I have changed only two files routes and build.sbt to use securesocial.

When I access /login url, I get following exception:

com.google.inject.ConfigurationException: Guice configuration errors:
1) Could not find a suitable constructor in securesocial.controllers.LoginPage. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
  at securesocial.controllers.LoginPage.class(LoginPage.scala:32)
  while locating securesocial.controllers.LoginPage
1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1026) ~[guice-4.0-beta4.jar:na]
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:985) ~[guice-4.0-beta4.jar:na]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1035) ~[guice-4.0-beta4.jar:na]
at Global.getControllerInstance(Global.java:51) ~[na:na]
at play.core.j.JavaGlobalSettingsAdapter.getControllerInstance(JavaGlobalSettingsAdapter.scala:50) ~[play_2.11-2.3.1.jar:2.3.1]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$31$$anonfun$apply$87.apply(routes_routing.scala:569) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$31$$anonfun$apply$87.apply(routes_routing.scala:569) ~[na:na]
at play.core.Router$HandlerInvokerFactory$$anon$13$$anon$14.call(Router.scala:217) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.Router$Routes$TaggingInvoker.call(Router.scala:464) ~[play_2.11-2.3.1.jar:2.3.1]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$31.apply(routes_routing.scala:569) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$31.apply(routes_routing.scala:569) ~[na:na]
at play.core.Router$Routes$class.call(Router.scala:326) ~[play_2.11-2.3.1.jar:2.3.1]
at Routes$.call(routes_routing.scala:17) ~[na:na]
at Routes$$anonfun$routes$1.applyOrElse(routes_routing.scala:568) ~[na:na]
at Routes$$anonfun$routes$1.applyOrElse(routes_routing.scala:324) ~[na:na]
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:218) ~[scala-library-2.11.1.jar:na]
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:214) ~[scala-library-2.11.1.jar:na]
at play.core.Router$Routes$class.handlerFor(Router.scala:454) ~[play_2.11-2.3.1.jar:2.3.1]
at Routes$.handlerFor(routes_routing.scala:17) ~[na:na]
at play.api.GlobalSettings$$anonfun$onRouteRequest$1$$anonfun$apply$1.apply(GlobalSettings.scala:128) ~[play_2.11-2.3.1.jar:2.3.1]
at play.api.GlobalSettings$$anonfun$onRouteRequest$1$$anonfun$apply$1.apply(GlobalSettings.scala:127) ~[play_2.11-2.3.1.jar:2.3.1]
at scala.Option.flatMap(Option.scala:170) ~[scala-library-2.11.1.jar:na]
at play.api.GlobalSettings$$anonfun$onRouteRequest$1.apply(GlobalSettings.scala:126) ~[play_2.11-2.3.1.jar:2.3.1]
at play.api.GlobalSettings$$anonfun$onRouteRequest$1.apply(GlobalSettings.scala:126) ~[play_2.11-2.3.1.jar:2.3.1]
at scala.Option.flatMap(Option.scala:170) ~[scala-library-2.11.1.jar:na]
at play.api.GlobalSettings$class.onRouteRequest(GlobalSettings.scala:126) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.j.JavaGlobalSettingsAdapter.play$core$j$JavaGlobalSettingsAdapter$$super$onRouteRequest(JavaGlobalSettingsAdapter.scala:31) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.j.JavaGlobalSettingsAdapter$$anonfun$onRouteRequest$2.apply(JavaGlobalSettingsAdapter.scala:31) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.j.JavaGlobalSettingsAdapter$$anonfun$onRouteRequest$2.apply(JavaGlobalSettingsAdapter.scala:31) ~[play_2.11-2.3.1.jar:2.3.1]
at scala.Option.getOrElse(Option.scala:120) ~[scala-library-2.11.1.jar:na]
at play.core.j.JavaGlobalSettingsAdapter.onRouteRequest(JavaGlobalSettingsAdapter.scala:31) ~[play_2.11-2.3.1.jar:2.3.1]
at play.api.GlobalSettings$class.onRequestReceived(GlobalSettings.scala:81) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.j.JavaGlobalSettingsAdapter.onRequestReceived(JavaGlobalSettingsAdapter.scala:14) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.server.Server$$anonfun$sendHandler$1$1.apply(Server.scala:53) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.server.Server$$anonfun$sendHandler$1$1.apply(Server.scala:52) ~[play_2.11-2.3.1.jar:2.3.1]
at scala.util.Success$$anonfun$map$1.apply(Try.scala:236) ~[scala-library-2.11.1.jar:na]
at scala.util.Try$.apply(Try.scala:191) ~[scala-library-2.11.1.jar:na]
at scala.util.Success.map(Try.scala:236) ~[scala-library-2.11.1.jar:na]
at play.core.server.Server$class.sendHandler$1(Server.scala:52) [play_2.11-2.3.1.jar:2.3.1]
at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:85) [play_2.11-2.3.1.jar:2.3.1]
at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:84) [play_2.11-2.3.1.jar:2.3.1]
at scala.util.Either$RightProjection.flatMap(Either.scala:522) [scala-library-2.11.1.jar:na]
at play.core.server.Server$class.getHandlerFor(Server.scala:84) [play_2.11-2.3.1.jar:2.3.1]
at play.core.server.NettyServer.getHandlerFor(NettyServer.scala:37) [play_2.11-2.3.1.jar:2.3.1]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$10.apply(PlayDefaultUpstreamHandler.scala:157) [play_2.11-2.3.1.jar:2.3.1]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$10.apply(PlayDefaultUpstreamHandler.scala:157) [play_2.11-2.3.1.jar:2.3.1]
at scala.util.Either.fold(Either.scala:99) [scala-library-2.11.1.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:142) [play_2.11-2.3.1.jar:2.3.1]
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.9.2.Final.jar:na]
at com.typesafe.netty.http.pipelining.HttpPipeliningHandler.messageReceived(HttpPipeliningHandler.java:62) [netty-http-pipelining-1.1.2.jar:na]
at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:108) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:459) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:536) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:318) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) [netty-3.9.2.Final.jar:na]
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) [netty-3.9.2.Final.jar:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_05]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_05]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_05]

colin.nie...@sdcsoftware.com

unread,
Sep 3, 2014, 11:04:23 AM9/3/14
to secure...@googlegroups.com
Tushar,

I had the same issue, in my controller I simple did the following.

@Singleton
class LoginPage @Inject()(implicit override val env: RuntimeEnvironment[User]) extends securesocial.controllers.BaseLoginPage[User]

@Singleton
class ProviderController @Inject()(implicit override val env: RuntimeEnvironment[User]) extends securesocial.controllers.BaseProviderController[User]


And then in the routes file you point it to this new implementation.

GET         /auth/login                         @controllers.LoginPage.login
GET         /auth/logout                        @controllers.LoginPage.logout

GET         /auth/authenticate/:provider        @controllers.ProviderController.authenticate(provider)
POST        /auth/authenticate/:provider        @controllers.ProviderController.authenticateByPost(provider)

->          /auth                               securesocial.Routes

Hope that helps.

Jonathan Lew

unread,
Oct 4, 2014, 3:11:27 PM10/4/14
to secure...@googlegroups.com
Having major troubles with deployment to Heroku using Play 2.3.2 and SecureSocial 3.0-M1.

Here's an example of the type of error I'm seeing:

  •  java.lang.NoSuchMethodError: securesocial.controllers.ReverseProviderController.authenticate(Ljava/lang/String;Lscala/Option;)Lplay/api/mvc/Call;
  •  at securesocial.core.services.RoutesService$Default.authenticationUrl(RoutesService.scala:67)
  •  at securesocial.core.OAuth2Provider$$anonfun$authenticate$4.apply(OAuth2Provider.scala:140)
  •  at securesocial.core.OAuth2Provider$$anonfun$authenticate$4.apply(OAuth2Provider.scala:137)
  •  at scala.util.Success$$anonfun$map$1.apply(Try.scala:206)
  •  at scala.util.Try$.apply(Try.scala:161)
  •  at scala.util.Success.map(Try.scala:206)
  •  at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
  •  at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
  •  at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
  •  at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107)
  •  at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
  •  at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
  •  at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
  •  at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
  •  at=error code=H12 desc="Request timeout" method=GET path="/authenticate/facebook" dyno=web.1 connect=1ms service=30001ms status=503 bytes=0

It seems that anything using the securesocial.RoutesService fails in a dist build on Heroku.

Of course, everything works fine using activator ~run locally.

Jorge Aliss

unread,
Oct 6, 2014, 9:29:19 AM10/6/14
to secure...@googlegroups.com
Are you sure the isn't an older version of SecureSocial cached on that Heroku instance? 

Jan Muller

unread,
Nov 7, 2014, 4:31:56 AM11/7/14
to secure...@googlegroups.com
Hi, I am trying to use LoginApi controller to sign in with Google account. But everytime it throws me the exception below. I assume, that after obtaining token on android device, this token is sent together with email to LoginApi controller and from this point, google servers are contacted to find out, if the token is correct and after it is ok, doSave method with mode SaveMode.SignUp() is invoked. Is it correct? 

[error] s.c.p.GoogleProvider - [securesocial] error retrieving profile information from Google
java.lang.ClassCastException: play.api.libs.json.JsUndefined cannot be cast to play.api.libs.json.JsArray
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$2.apply(GoogleProvider.scala:66) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$2.apply(GoogleProvider.scala:53) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at scala.util.Success$$anonfun$map$1.apply(Try.scala:236) ~[scala-library-2.11.1.jar:na]
at scala.util.Try$.apply(Try.scala:191) ~[scala-library-2.11.1.jar:na]
at scala.util.Success.map(Try.scala:236) ~[scala-library-2.11.1.jar:na]
[error] s.c.p.GoogleProvider - [securesocial] error authenticating user via api
securesocial.core.AuthenticationException: null
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$1.applyOrElse(GoogleProvider.scala:74) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$1.applyOrElse(GoogleProvider.scala:70) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.1.jar:na]
at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:215) ~[scala-library-2.11.1.jar:na]
at scala.util.Try$.apply(Try.scala:191) ~[scala-library-2.11.1.jar:na]
[error] play - Cannot invoke the action, eventually got an error: securesocial.core.AuthenticationException
[error] application -

! @6k5hfjhad - Internal server error, for (POST) [/auth/api/authenticate/google] ->

play.api.Application$$anon$1: Execution exception[[AuthenticationException: null]]
at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.5.jar:2.3.5]
at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.5.jar:2.3.5]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.5.jar:2.3.5]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.5.jar:2.3.5]
at scala.Option.map(Option.scala:145) [scala-library-2.11.1.jar:na]
Caused by: securesocial.core.AuthenticationException: null
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$1.applyOrElse(GoogleProvider.scala:74) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at securesocial.core.providers.GoogleProvider$$anonfun$fillProfile$1.applyOrElse(GoogleProvider.scala:70) ~[securesocial_2.11-master-SNAPSHOT.jar:master-SNAPSHOT]
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.1.jar:na]
at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:215) ~[scala-library-2.11.1.jar:na]

Jan Muller

unread,
Nov 7, 2014, 6:32:37 AM11/7/14
to secure...@googlegroups.com
Facebook auth is working properly.
Message has been deleted

Amir Karimi

unread,
Nov 26, 2014, 4:30:01 AM11/26/14
to secure...@googlegroups.com
It's amazing.

Regarding the Async support I have a problem with ViewTemplates trait. I need to render menu and other dynamic stuffs in SecureSocial views so I need the methods to be Async (return Future[Html] instead of Html).

raunak

unread,
Feb 2, 2015, 10:44:42 AM2/2/15
to secure...@googlegroups.com
Jorge, do you have an eta in mind for the upcoming version 3 release? 
I'm happy to help in anyway I can to speed things up - please do let me know how/where. 

Mihai Simioana

unread,
Feb 19, 2015, 11:43:19 PM2/19/15
to secure...@googlegroups.com
I had similar problems with guice integration and I wrote a short article about it here. Hope it helps or there are comments to improve it:

Daniel Beck

unread,
Feb 20, 2015, 3:14:13 AM2/20/15
to secure...@googlegroups.com

Dear Mihai,

the link doesn't work.

Daniel

Manohar Jonnalagedda

unread,
Apr 20, 2015, 9:17:19 AM4/20/15
to secure...@googlegroups.com
Hello,



On Wednesday, May 7, 2014 at 6:12:21 AM UTC+2, Jorge Aliss wrote:

9)  Renamed Identity to BasicProfile
A BasicProfile is the same set of data that the Identity trait used to hold.  The module creates a BasicProfile when an authentication is successful and passes the instance to your app, you can then return an instance of your own object and use it in the actions.  

All the object copying that was using the SocialUser class is gone. I refactored the providers a bit so that is not needed anymore. 


It would be great if BasicProfile (or at least what a UserService expects us to return) were abstract. While a BasicProfile would suffice in many cases, there is one general case where I think it does not: handling multiple profiles in a classic relational database (MySQL for instance). An accepted way to handle multiple profiles is to have an extra field in the table that refers to the main id [1]. As a result, I will need to extend BasicProfile to add at least an extra field. The problem is that BasicProfile is a case class [2]. I could always decouple the representation of my table from a BasicProfile, but that seems to me as a slightly convoluted design.

Happy to know if I could redesign things differently!

Cheers,
Manohar

[1] https://github.com/jaliss/securesocial/issues/14, especially the last comments.
[2] Sure, I could create my own extractors for my subtype of BasicProfile, seems boilerplate-y
Could BasicProfile be abstract? While Bas
Reply all
Reply to author
Forward
0 new messages