QnaList > Groups > Play-Framework > Nov 2012
faq

[play-framework][2.0.4][SecureSocial] New Release

Hi All,
I just released a new version of SecureSocial that includes:
- Improved signup flow (validates email before allowing registration)
- Added reset password functionality
- Added email notifications�
- Added a way to customise views �& mails (via TemplatesPlugin)
- Added a setting to enable HTTPS in the URLSs for OAUTH callbacks and routes�
- Replaced displayName in SocialUser for firstName, lastName and fullName fields
I also added a User Guide which is available here:�http://www.securesocial.ws.�
Cheers,
Jorge

asked Nov 11 2012 at 21:25

Jorge Aliss's gravatar image



24 Replies for : [play-framework][2.0.4][SecureSocial] New Release
Congratulations!
A lot of functionalities have been added in this release.
I am building a new webapp based on Play 2.1-RC.
I would like to use SecureSocial username/password with Play 2.1. Is it possible? Do I have to change something? If possible, can you give me any instructions?
Best regards,
giovanni
- show quoted text -
- show quoted text -
-- 
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to [email protected].
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

answered Nov 11 2012 at 23:39

Giovanni's gravatar image


Thanks!�I have not tried SecureSocial with Play 2.1 yet. �Will try to test that today and see how to make it work with that version.
Jorge
- show quoted text -

answered Nov 12 2012 at 06:59

Jorge Aliss's gravatar image


OK.
I am trying to develop the new webapp with the new software stack (Scala, Akka, Play, etc.)
It is a pity to go back to the old software stack because of SecureSocial.
I wait for your feedback.
Best regards,
giovanni
- show quoted text -

answered Nov 12 2012 at 19:33

Giovanni's gravatar image


I want to use a database to persist the users, so I need to replace the InMemoryUserService with another class, which retrieves/stores the users to a database.
I have to create a database table for the users, containing the following fields:
- id
- first_name
- last_name
- email
Do I have to create also a database table for the tokens?
Best regards,
giovanni
- show quoted text -

answered Nov 12 2012 at 19:37

Giovanni's gravatar image


In the USER table I also added the password.
I am using ANORM to access the database.
First I tried with H2, but i always get an error on a lock on the table USER.
Now I am trying with mysql:
mysql> CREATE TABLE USER(ID VARCHAR(100) NOT NULL, FIRST_NAME VARCHAR(200), LAST_NAME VARCHAR(200), EMAIL VARCHAR(100),� PASSWORD VARCHAR(100));
From the log, I see that the "save" function is called 2 times:
- when I sign up
- when I log in
Is it correct?
Now my implementation doesn't work, because it expects to find only 1 row in the database for each user, instead it finds 2 rows.
What is the correct behavior? How should I have to implement the persistence in the DB?
Best regards,
giovanni
- show quoted text -

answered Nov 13 2012 at 20:21

Giovanni's gravatar image


I succeded to make a persistent UserServicePlugin, which seems to work. See the class DbUserService hereunder. This class considers only the "userpass" provider, which is fixed in the code.
But I am not sure that it is the correct way. My doubts are:
in the "save" function I distinguished the cases in which the user already exists in the DB; if it exists -> update, otherwise -> insert
I didn't persist the "tokens" to the DB; I don't understand well the use of the tokens 
Any suggestions will be appreciated.
Best regards,
giovanni
package service
import play.api.{Logger, Application}
import securesocial.core.{UserServicePlugin, UserId, SocialUser}
import java.util.UUID
import org.joda.time.DateTime
import securesocial.core.providers.Token
import securesocial.core.AuthenticationMethod
import securesocial.core.PasswordInfo
import play.api.db._
import anorm._
import play.api.Play.current
/**
�* A Database user service in Scala
�*
�*/
class DbUserService(application: Application) extends UserServicePlugin(application) {
�
// �private var users = Map[String, SocialUser]()
� private var tokens = Map[String, Token]()
� /**
� �* find
� �*/
� def find(id: UserId) = {
� � if (Logger.isDebugEnabled) {
� � � Logger.debug("find...")
� � � Logger.debug("id = %s".format(id.id))
� � }
� �
� � DB.withConnection { implicit c =>
� � � val sqlQuery = SQL(
� � � � � """
� � � � � � select * from USER
� � � � � � where id = {id};
� � � � � """).on("id" -> id.id)
� � � // Transform the resulting Stream[Row] to a List[SocialUser]
� � � val users = sqlQuery().map(row =>
� � � � SocialUser(
� � � � � � UserId(row[String]("id"), "userpass"),
� � � � � � row[String]("first_name"),
� � � � � � row[String]("last_name"),
� � � � � � row[String]("first_name") + " " + row[String]("last_name"),
� � � � � � row[Option[String]]("email"),
� � � � � � None,
� � � � � � AuthenticationMethod("userPassword"),
� � � � � � None,
� � � � � � None,
� � � � � � Some(PasswordInfo(row[String]("password"), None))
� � � � )).toList
� � � �
� � � val socialUser = if (users.size == 1) Some(users(0)) else None
� � �
� � � if (Logger.isDebugEnabled) {
� � � � Logger.debug("socialUser = %s".format(socialUser))
� � � }
� � �
� � � socialUser
� � } // end DB
� �
� } // end find
�
� def findByEmail(email: String, providerId: String): Option[SocialUser] = {
� �
� � if (Logger.isDebugEnabled) {
� � � Logger.debug("findByEmail...")
� � � Logger.debug("email = %s".format(email))
� � � Logger.debug("providerId = %s".format(providerId))
� � }
� �
� � DB.withConnection { implicit c =>
� � � val sqlQuery = SQL(
� � � � � """
� � � � � � select * from USER
� � � � � � where email = {email};
� � � � � """).on("email" -> email)
� � � // Transform the resulting Stream[Row] to a List[SocialUser]
� � � val users = sqlQuery().map(row =>
� � � � SocialUser(
� � � � � � UserId(row[String]("id"), "userpass"),
� � � � � � row[String]("first_name"),
� � � � � � row[String]("last_name"),
� � � � � � row[String]("first_name") + " " + row[String]("last_name"),
� � � � � � row[Option[String]]("email"),
� � � � � � None,
� � � � � � AuthenticationMethod("userPassword"),
� � � � � � None,
� � � � � � None,
� � � � � � Some(PasswordInfo(row[String]("password"), None))
� � � � )).toList
� � � �
� � � val socialUser = if (users.size == 1) Some(users(0)) else None
� � �
� � � if (Logger.isDebugEnabled) {
� � � � Logger.debug("socialUser = %s".format(socialUser))
� � � }
� � �
� � � socialUser
� � } // end DB
� �
� } // end findByEmail
�
� def save(user: SocialUser) {
� � if (Logger.isDebugEnabled) {
� � � Logger.debug("save...")
� � � Logger.debug("user = %s".format(user))
� � }
� � DB.withConnection { implicit c =>
� � �
� � � val sqlSelectQuery = SQL(
� � � � � """
� � � � � � select * from USER
� � � � � � where id = {id};
� � � � � """).on("id" -> user.id.id)
� � � val users = sqlSelectQuery().map(row =>
� � � � SocialUser(
� � � � � � UserId(row[String]("id"), "userpass"),
� � � � � � row[String]("first_name"),
� � � � � � row[String]("last_name"),
� � � � � � row[String]("first_name") + " " + row[String]("last_name"),
� � � � � � row[Option[String]]("email"),
� � � � � � None,
� � � � � � AuthenticationMethod("userPassword"),
� � � � � � None,
� � � � � � None,
� � � � � � Some(PasswordInfo(row[String]("password"), None))
� � � � )).toList
� � � �
� � � val socialUser = if (users.size == 1) Some(users(0)) else None
� � �
� � � if (Logger.isDebugEnabled) {
� � � � Logger.debug("socialUser = %s".format(socialUser))
� � � }
� � �
� � � if (socialUser == None) { // user not exists
� � � � // create a new user
� � � � val sqlQuery = SQL(
� � � � � """
� � � � � � insert into USER
� � � � � � � (id, first_name, last_name, email, password)
� � � � � � values
� � � � � � � ({id}, {first_name}, {last_name}, {email}, {password})
� � � � � """).on(
� � � � � � 'id -> user.id.id,
� � � � � � 'first_name -> user.firstName,
� � � � � � 'last_name -> user.lastName,
� � � � � � 'email -> user.email,
� � � � � � 'password -> user.passwordInfo.get.password)
� � � � val result: Int = sqlQuery.executeUpdate()
� � � � if (Logger.isDebugEnabled) {
� � � � � Logger.debug("result = %s".format(result))
� � � � }
� � � } else { // user exists
� � � �
� � � � // update the user
� � � � val sqlQuery = SQL(
� � � � � """
� � � � � � update USER
� � � � � � � set id = {id},
� � � � � � � � � first_name = {first_name},
� � � � � � � � � last_name = {last_name},
� � � � � � � � � email = {email},
� � � � � � � � � password = {password}
� � � � � � � where id = {id}
� � � � � """).on(
� � � � � � 'id -> user.id.id,
� � � � � � 'first_name -> user.firstName,
� � � � � � 'last_name -> user.lastName,
� � � � � � 'email -> user.email,
� � � � � � 'password -> user.passwordInfo.get.password)
� � � � val result: Int = sqlQuery.executeUpdate()
� � � � if (Logger.isDebugEnabled) {
� � � � � Logger.debug("result = %s".format(result))
� � � � }
� � � } // end else
� � } // end DB
� �
� } // end save
�
� def save(token: Token) {
� � tokens += (token.uuid -> token)
� }
� def findToken(token: String): Option[Token] = {
� � tokens.get(token)
� }
� def deleteToken(uuid: String) {
� � tokens -= uuid
� }
� def deleteTokens() {
� � tokens = Map()
� }
� def deleteExpiredTokens() {
� � tokens = tokens.filter(!_._2.isExpired)
� }
�
�
} // end DbUserService
- show quoted text -

answered Nov 14 2012 at 01:41

Giovanni's gravatar image


Hi Giovanni,
You are right about the save function. �You need to distinguish the save/update cases. �A better name could be saveOrUpdate maybe :)
Why are you hardcoding the userpass in the code? When SecureSocial calls your save() method it will give you the provider id that was used by the user. �So you can just save that value as a String in the db.�
The tokens are used to identify sign up and reset password requests. You need to persist them as well. �Holding them in memory is not a good idea (for the sample is fine, but not for production), first you're keeping state in the server and if your app restarts the tokens will be gone. �If a user tries to use a link sent by the app it will not work (tokens expire after 1 hour though). � ��
Hope this makes it clearer.
Jorge
- show quoted text -

answered Nov 14 2012 at 07:55

Jorge Aliss's gravatar image


Hi Jorge,
thank you for your explanations.
I will change the DbUserService according to your information.
I will let you know the progress.
Best regards,
giovanni
- show quoted text -

answered Nov 14 2012 at 17:34

Giovanni's gravatar image


Any news about running the SecureSocial on Play 2.1?
giovanni
- show quoted text -

answered Nov 14 2012 at 17:38

Giovanni's gravatar image


Not yet, but will try to test this before the end of the week. � I was doing some work to simplify the installation of the module and finished it today.
You might want to update the version you're using.
Jorge
- show quoted text -
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 14 2012 at 17:52

Jorge Aliss's gravatar image


OK, great!
giovanni
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 14 2012 at 18:00

Giovanni's gravatar image


I tried the new release, but I have some problems on the CSS on the index page.
I followed the new installation instructions, but the index page of the demo is displayed without CSS.
The only changes I did are:
I deleted the "modules" directory
I changed the Build.scala
Build.scala:
import sbt._
import Keys._
import PlayProject._
object ApplicationBuild extends Build {
��� val appName�������� = "securesocial-testing"
��� val appVersion����� = "1.0-SNAPSHOT"
//��� val ssDependencies = Seq(
//����� // Add your project dependencies here,
//����� "com.typesafe" %% "play-plugins-util" % "2.0.3",
//����� "com.typesafe" %% "play-plugins-mailer" % "2.0.4",
//����� "org.mindrot" % "jbcrypt" % "0.3m"
//��� )
// 
//��� val secureSocial = PlayProject(
//��� ��� "securesocial", appVersion, ssDependencies, mainLang = SCALA, path = file("modules/securesocial")
//��� ).settings(
//����� resolvers ++= Seq(
//������� "jBCrypt Repository" at "http://repo1.maven.org/maven2/org/",
//������� "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
//����� )
//��� )
��� val appDependencies = Seq(
��� ��� "mysql" % "mysql-connector-java" % "5.1.18",
��� ��� "securesocial" % "securesocial_2.9.1" % "2.0.5"
��� )
//��� val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
//����� // Add your own project settings here����� 
//��� ).dependsOn(secureSocial).aggregate(secureSocial)
��� 
��� val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
����� // Add your own project settings here����� 
����� resolvers += Resolver.url("SecureSocial Repository", url("http://securesocial.ws/repository/releases/"))(Resolver.ivyStylePatterns)
��� )
}
Best regards,
giovanni
- show quoted text -

answered Nov 14 2012 at 18:22

Giovanni's gravatar image


I think you did not get the latest demo app from the repository, right?
- show quoted text -
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 14 2012 at 18:29

Jorge Aliss's gravatar image


Yes, right. I used the demo app of the previous release.
giovanni
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 14 2012 at 18:33

Giovanni's gravatar image


I added the "bootstrap" directory under the "public" directory. Now it works.
giovanni
- show quoted text -

answered Nov 14 2012 at 18:56

Giovanni's gravatar image


Regarding the persistence of the tokens, also in this case do I have to distinguish between insert and update for the function save(token: Token)?
giovanni
- show quoted text -

answered Nov 14 2012 at 23:53

Giovanni's gravatar image


No, they are saved or deleted. Never updated. �Make sure you distinguish between the tokens created for sign ups and password resets though.
I saw your findByEmail implementation, notice that the method also receives a providerId. �The match must be made with the email AND the provider id.�
Jorge
- show quoted text -
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 15 2012 at 03:22

Jorge Aliss's gravatar image


OK. Thanks.
giovanni
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 15 2012 at 17:29

Giovanni's gravatar image


I have implemented also the DB persistence of tokens. You can see the attached file.
The mysql tables are:
Table USER
----------
CREATE TABLE USER(ID VARCHAR(100) NOT NULL, PROVIDER VARCHAR(100), FIRST_NAME VARCHAR(200), LAST_NAME VARCHAR(200), EMAIL VARCHAR(100), PASSWORD VARCHAR(100));
Table TOKEN
-----------
CREATE TABLE TOKEN (UUID VARCHAR(100) NOT NULL PRIMARY KEY, EMAIL VARCHAR(100), CREATION_TIME DATETIME, EXPIRATION_TIME DATETIME, IS_SIGN_UP BOOLEAN);
I still have to implement the match of email AND provider id in findByEmail.
After I finish the correct implementation, maybe we can include the DbUserService in the demo app.
Best regards,
giovanni
- show quoted text -

answered Nov 15 2012 at 19:23

Giovanni's gravatar image


Cool. Any plans for SSO in a corporate Windows environment? e.g. NTLMv2, Kerberos

answered Nov 15 2012 at 21:29

Andy Czerwonka's gravatar image


Hi Andy,
Not for now. �But will look into it and consider it in the roadmap. �I need to add other things first.
Cheers,
Jorge
On Fri, Nov 16, 2012 at 1:22 AM, Andy Czerwonka  wrote:
Cool. Any plans for SSO in a corporate Windows environment? e.g. NTLMv2, Kerberos
--

answered Nov 16 2012 at 05:40

Jorge Aliss's gravatar image


giovanni, it'd be very useful for me to have a look at your UserServicePlugin.
let me know if that's possibile.
thank you
-marco
https://github.com/mfirry
- show quoted text -

answered Nov 19 2012 at 14:43

Marco F's gravatar image


+1 for NTLM support!!!!
and great work, jorge, congrats on the new release!
- show quoted text -

answered Nov 19 2012 at 14:50

sas's gravatar image


I attach my DbUserService. It is working with SecureSocial 2.0.6.
You can give me your feedback, so we can improve it.
If it is worth, Jorge can you include it in the next release of SecureSocial as demo?
Regards
giovanni
- show quoted text -
- show quoted text -
-- 
�
�

answered Nov 19 2012 at 17:28

Giovanni's gravatar image


Related discussions

Tagged

Group Play-framework

asked Nov 11 2012 at 21:25

active Nov 19 2012 at 17:28

posts:25

users:5

Play-framework

©2013 QnaList.com