Reputation: 2983
I have been working on learning how to use the Play framework. It is my understanding that plugins can be use to add functionality that others have developed. Maybe I should be calling it a module? I read that SercureSocial is one of the best modules available for authentication. But the documentation isn't really getting me anywhere. Can someone help me understand how to add the master-snapshot to my existing java project?
Lets assume that I performed activator new my-first-app play-scala activator eclipse The I imported into eclipse the project
The next step is to try to follow directions from the following url
http://securesocial.ws/guide/installation.html
After reading that I am still lost.
There is no Build.scala file, but I see there is a build.sbt file. Do I add this block to the build.sbt file?
object ApplicationBuild extends Build {
val appName = "my-first-app"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"ws.securesocial" %% "securesocial" % "master-SNAPSHOT"
)
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers += Resolver.sonatypeRepo("releases")
)
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers += Resolver.sonatypeRepo("snapshots")
)
After copying the block above, I created the ply.plugins file in the conf folder. Then I copied all the plugins to the file and saved
1500:com.typesafe.plugin.CommonsMailerPlugin
9994:securesocial.core.DefaultAuthenticatorStore
9995:securesocial.core.DefaultIdGenerator
9996:securesocial.core.providers.utils.DefaultPasswordValidator
9997:securesocial.controllers.DefaultTemplatesPlugin
9998:your.user.Service.Implementation <-- Important: You need to change this
9999:securesocial.core.providers.utils.BCryptPasswordHasher
10000:securesocial.core.providers.TwitterProvider
10001:securesocial.core.providers.FacebookProvider
10002:securesocial.core.providers.GoogleProvider
10003:securesocial.core.providers.LinkedInProvider
10004:securesocial.core.providers.UsernamePasswordProvider
10005:securesocial.core.providers.GitHubProvider
10006:securesocial.core.providers.FoursquareProvider
10007:securesocial.core.providers.XingProvider
10008:securesocial.core.providers.VkProvider
10009:securesocial.core.providers.InstagramProvider
Next, I copy all the routes into the routes file
# Login page
GET /login securesocial.controllers.LoginPage.login
GET /logout securesocial.controllers.LoginPage.logout
# User Registration and password handling
GET /signup securesocial.controllers.Registration.startSignUp
POST /signup securesocial.controllers.Registration.handleStartSignUp
GET /signup/:token securesocial.controllers.Registration.signUp(token)
POST /signup/:token securesocial.controllers.Registration.handleSignUp(token)
GET /reset securesocial.controllers.Registration.startResetPassword
POST /reset securesocial.controllers.Registration.handleStartResetPassword
GET /reset/:token securesocial.controllers.Registration.resetPassword(token)
POST /reset/:token securesocial.controllers.Registration.handleResetPassword(token)
GET /password securesocial.controllers.PasswordChange.page
POST /password securesocial.controllers.PasswordChange.handlePasswordChange
# Providers entry points
GET /authenticate/:provider securesocial.controllers.ProviderController.authenticate(provider)
POST /authenticate/:provider securesocial.controllers.ProviderController.authenticateByPost(provider)
GET /not-authorized securesocial.controllers.ProviderController.notAuthorized
I then try to run the project and I get the following error
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: ws.securesocial#securesocial;2.1.4: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes.
[warn] ws.securesocial:securesocial:2.1.4 (scalaVersion=2.10, sbtVersion=0.13)
[warn]
sbt.ResolveException: unresolved dependency: ws.securesocial#securesocial;2.1.4:not found
at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:217)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:126)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:125)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:103)
at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:48)
at sbt.IvySbt$$anon$3.call(Ivy.scala:57)
at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
at xsbt.boot.Using$.withResource(Using.scala:10)
at xsbt.boot.Using$.apply(Using.scala:9)
at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at sbt.IvySbt.withDefaultLogger(Ivy.scala:57)
at sbt.IvySbt.withIvy(Ivy.scala:98)
at sbt.IvySbt.withIvy(Ivy.scala:94)
at sbt.IvySbt$Module.withModule(Ivy.scala:115)
at sbt.IvyActions$.update(IvyActions.scala:125)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1223)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1221)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1244)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1242)
at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:35)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1246)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1241)
at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:45)
at sbt.Classpaths$.cachedUpdate(Defaults.scala:1249)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1214)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1192)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[error] (*:update) sbt.ResolveException: unresolved dependency: ws.securesocial#securesocial;2.1.4: not found
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
Upvotes: 1
Views: 1085
Reputation: 3008
Can someone help me understand how to add the master-snapshot to my existing java project?
I have only tried with the Scala version and not Java, but I hope the following helps a little bit.
In your build.sbt file add the following line to you libraryDependencies:
"ws.securesocial" %% "securesocial" % "master-SNAPSHOT"
There is no Build.scala file, but I see there is a build.sbt file. Do I add this block to the build.sbt file?
The only other thing you need to add to build.sbt is the Sonatype OSS Snapshots repository URL:
resolvers +=
"Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
After copying the block above, I created the ply.plugins file in the conf folder. Then I copied all the plugins to the file and saved
The only plugin you need configured in the play.plugins file is the CommonsMailerPlugin:
1500:com.typesafe.plugin.CommonsMailerPlugin
Next, I copy all the routes into the routes file
Try the below as an example instead of what you had which is based on an older version of securesocal:
# your secure page
GET / @controllers.Application.index
# securesocial routes
GET /login @securesocial.controllers.LoginPage.login
GET /logout @securesocial.controllers.LoginPage.logout
-> /auth securesocial.Routes
In order to get a working example running you need the following:
securesocial.conf https://github.com/jaliss/securesocial/blob/master/samples/scala/demo/conf/securesocial.conf
You would need to configure your smtp mail settings and any securesocial configuration.
InMemoryUserService
/**
* Copyright 2012 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package service
import play.api.Logger
import securesocial.core._
import securesocial.core.providers.{ UsernamePasswordProvider, MailToken }
import scala.concurrent.Future
import securesocial.core.services.{ UserService, SaveMode }
/**
* A Sample In Memory user service in Scala
*
* IMPORTANT: This is just a sample and not suitable for a production environment since
* it stores everything in memory.
*/
class InMemoryUserService extends UserService[DemoUser] {
val logger = Logger("application.controllers.InMemoryUserService")
//
var users = Map[(String, String), DemoUser]()
//private var identities = Map[String, BasicProfile]()
private var tokens = Map[String, MailToken]()
def find(providerId: String, userId: String): Future[Option[BasicProfile]] = {
if (logger.isDebugEnabled) {
logger.debug("users = %s".format(users))
}
val result = for (
user <- users.values;
basicProfile <- user.identities.find(su => su.providerId == providerId && su.userId == userId)
) yield {
basicProfile
}
Future.successful(result.headOption)
}
def findByEmailAndProvider(email: String, providerId: String): Future[Option[BasicProfile]] = {
if (logger.isDebugEnabled) {
logger.debug("users = %s".format(users))
}
val someEmail = Some(email)
val result = for (
user <- users.values;
basicProfile <- user.identities.find(su => su.providerId == providerId && su.email == someEmail)
) yield {
basicProfile
}
Future.successful(result.headOption)
}
private def findProfile(p: BasicProfile) = {
users.find {
case (key, value) if value.identities.exists(su => su.providerId == p.providerId && su.userId == p.userId) => true
case _ => false
}
}
private def updateProfile(user: BasicProfile, entry: ((String, String), DemoUser)): Future[DemoUser] = {
val identities = entry._2.identities
val updatedList = identities.patch(identities.indexWhere(i => i.providerId == user.providerId && i.userId == user.userId), Seq(user), 1)
val updatedUser = entry._2.copy(identities = updatedList)
users = users + (entry._1 -> updatedUser)
Future.successful(updatedUser)
}
def save(user: BasicProfile, mode: SaveMode): Future[DemoUser] = {
mode match {
case SaveMode.SignUp =>
val newUser = DemoUser(user, List(user))
users = users + ((user.providerId, user.userId) -> newUser)
Future.successful(newUser)
case SaveMode.LoggedIn =>
// first see if there is a user with this BasicProfile already.
findProfile(user) match {
case Some(existingUser) =>
updateProfile(user, existingUser)
case None =>
val newUser = DemoUser(user, List(user))
users = users + ((user.providerId, user.userId) -> newUser)
Future.successful(newUser)
}
case SaveMode.PasswordChange =>
findProfile(user).map { entry => updateProfile(user, entry) }.getOrElse(
// this should not happen as the profile will be there
throw new Exception("missing profile)")
)
}
}
def link(current: DemoUser, to: BasicProfile): Future[DemoUser] = {
if (current.identities.exists(i => i.providerId == to.providerId && i.userId == to.userId)) {
Future.successful(current)
} else {
val added = to :: current.identities
val updatedUser = current.copy(identities = added)
users = users + ((current.main.providerId, current.main.userId) -> updatedUser)
Future.successful(updatedUser)
}
}
def saveToken(token: MailToken): Future[MailToken] = {
Future.successful {
tokens += (token.uuid -> token)
token
}
}
def findToken(token: String): Future[Option[MailToken]] = {
Future.successful { tokens.get(token) }
}
def deleteToken(uuid: String): Future[Option[MailToken]] = {
Future.successful {
tokens.get(uuid) match {
case Some(token) =>
tokens -= uuid
Some(token)
case None => None
}
}
}
// def deleteTokens(): Future {
// tokens = Map()
// }
def deleteExpiredTokens() {
tokens = tokens.filter(!_._2.isExpired)
}
override def updatePasswordInfo(user: DemoUser, info: PasswordInfo): Future[Option[BasicProfile]] = {
Future.successful {
for (
found <- users.values.find(_ == user);
identityWithPasswordInfo <- found.identities.find(_.providerId == UsernamePasswordProvider.UsernamePassword)
) yield {
val idx = found.identities.indexOf(identityWithPasswordInfo)
val updated = identityWithPasswordInfo.copy(passwordInfo = Some(info))
val updatedIdentities = found.identities.patch(idx, Seq(updated), 1)
val updatedEntry = found.copy(identities = updatedIdentities)
users = users + ((updatedEntry.main.providerId, updatedEntry.main.userId) -> updatedEntry)
updated
}
}
}
override def passwordInfoFor(user: DemoUser): Future[Option[PasswordInfo]] = {
Future.successful {
for (
found <- users.values.find(u => u.main.providerId == user.main.providerId && u.main.userId == user.main.userId);
identityWithPasswordInfo <- found.identities.find(_.providerId == UsernamePasswordProvider.UsernamePassword)
) yield {
identityWithPasswordInfo.passwordInfo.get
}
}
}
}
// a simple User class that can have multiple identities
case class DemoUser(main: BasicProfile, identities: List[BasicProfile])
Global.scala
Scala https://github.com/jaliss/securesocial/blob/master/samples/scala/demo/app/Global.scala
Java https://github.com/jaliss/securesocial/blob/master/samples/java/demo/app/Global.java
/**
* Copyright 2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import controllers.CustomRoutesService
import java.lang.reflect.Constructor
import securesocial.core.RuntimeEnvironment
import service.{ DemoUser, MyEventListener, InMemoryUserService }
object Global extends play.api.GlobalSettings {
/**
* The runtime environment for this sample app.
*/
object MyRuntimeEnvironment extends RuntimeEnvironment.Default[DemoUser] {
override implicit val executionContext = play.api.libs.concurrent.Execution.defaultContext
override lazy val routes = new CustomRoutesService()
override lazy val userService: InMemoryUserService = new InMemoryUserService()
override lazy val eventListeners = List(new MyEventListener())
}
/**
* An implementation that checks if the controller expects a RuntimeEnvironment and
* passes the instance to it if required.
*
* This can be replaced by any DI framework to inject it differently.
*
* @param controllerClass
* @tparam A
* @return
*/
override def getControllerInstance[A](controllerClass: Class[A]): A = {
val instance = controllerClass.getConstructors.find { c =>
val params = c.getParameterTypes
params.length == 1 && params(0) == classOf[RuntimeEnvironment[DemoUser]]
}.map {
_.asInstanceOf[Constructor[A]].newInstance(MyRuntimeEnvironment)
}
instance.getOrElse(super.getControllerInstance(controllerClass))
}
}
Secure Application controller
package controllers
import play.api._
import play.api.mvc._
import securesocial.core._
import service.DemoUser
class Application(override implicit val env: RuntimeEnvironment[DemoUser]) extends SecureSocial[DemoUser] {
def index = SecuredAction { implicit request =>
Ok(views.html.index(request.user.main))
}
}
Secure page - index.scala.html
@(user: securesocial.core.BasicProfile)(implicit request: RequestHeader, env: securesocial.core.RuntimeEnvironment[service.DemoUser])
@main("Secure Page") {
<h2>User Id:@user.userId</h2>
<hr>
<a class="btn" href="@securesocial.controllers.routes.LoginPage.logout()">Logout</a>
}
Upvotes: 2
Reputation: 303
I've been going through this myself the last couple days. At this point in time, I suggest you ignore the documentation. It is not up to date (documentation is for 2, but 3 seems to be needed for play 2.3.x). Stuff like the play.plugins send you down the wrong path.
Piecing together an installation for putting M3 on 2.3.X has been rough, but I do think I have it working in Java. These resources have been helpful to me. Pull stuff like your .sbt settings from the sample.
First, read the high level overview. Second, clone the sample and get it to run. This SO on running it is helpful. Third, migrate code from the sample into your local tree. Once you get that going, you may see there is no styling. See this for info on how to get the css/js showing up.
Upvotes: 3
Reputation: 13985
Well... libraryDependencies
is a SettingKey[ Seq[ ModuleId ] ]
.
Now, SettingKey[ Seq[ ModuleId ] ]
can be seen as something similar to a Seq
or List
and it provides similar kind of functionalities.
So... you can just add your new dependencies to it, just like you will add to any other Seq
or List
.
libraryDependencies += "ws.securesocial" %% "securesocial" % "2.1.4"
Upvotes: 0