├── HEAD ├── system.properties ├── conf ├── play.plugins ├── routes ├── silhouette.conf └── application.conf ├── config ├── description ├── app ├── modules │ ├── .DS_Store │ └── cake │ │ ├── UserServiceModule.scala │ │ ├── AvatarServiceModule.scala │ │ ├── MailServiceModule.scala │ │ ├── CredentialsProviderModule.scala │ │ ├── AuthInfoServiceModule.scala │ │ ├── AuthenticatorServiceModule.scala │ │ ├── EnvironmentModule.scala │ │ └── SocialProviderModule.scala ├── views │ └── authentication │ │ └── mails │ │ └── welcomeEmail.scala.html ├── models │ ├── users │ │ ├── BaseInfo.scala │ │ └── User.scala │ ├── authorizations │ │ └── Roles.scala │ └── daos │ │ ├── OAuth1InfoDAO.scala │ │ ├── OAuth2InfoDAO.scala │ │ └── PasswordInfoDAO.scala ├── security │ ├── models │ │ ├── SignUp.scala │ │ ├── Token.scala │ │ └── SocialAuth.scala │ └── formatters │ │ └── json │ │ ├── OAuth1InfoFormats.scala │ │ ├── PasswordInfoFormats.scala │ │ ├── CredentialFormats.scala │ │ └── OAuth2InfoFormats.scala ├── formatters │ └── json │ │ ├── CredentialFormat.scala │ │ ├── BaseInfoFormats.scala │ │ ├── SocialAuthFormat.scala │ │ └── UserFormats.scala ├── utils │ └── responses │ │ └── rest │ │ ├── Good.scala │ │ └── Bad.scala ├── controllers │ ├── RestApplicationController.scala │ └── security │ │ └── rest │ │ ├── RestCredentialsAuthController.scala │ │ ├── RestSignUpController.scala │ │ └── RestSocialAuthController.scala ├── services │ ├── MailService.scala │ ├── UserService.scala │ └── UserServicesImpl.scala └── Global.scala ├── public ├── images │ ├── favicon.png │ ├── silhouette.png │ └── providers │ │ ├── google.png │ │ ├── facebook.png │ │ └── twitter.png ├── javascripts │ └── hello.js └── stylesheets │ └── main.css ├── project ├── build.properties └── plugins.sbt ├── LICENSE ├── .gitignore └── README.md /HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /system.properties: -------------------------------------------------------------------------------- 1 | java.runtime.version=1.7 -------------------------------------------------------------------------------- /conf/play.plugins: -------------------------------------------------------------------------------- 1 | 1500:com.typesafe.plugin.CommonsMailerPlugin -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = true 5 | -------------------------------------------------------------------------------- /description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /app/modules/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/app/modules/.DS_Store -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/silhouette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/public/images/silhouette.png -------------------------------------------------------------------------------- /public/javascripts/hello.js: -------------------------------------------------------------------------------- 1 | if (window.console) { 2 | console.log("Welcome to your Play application's JavaScript!"); 3 | } -------------------------------------------------------------------------------- /public/images/providers/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/public/images/providers/google.png -------------------------------------------------------------------------------- /public/images/providers/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/public/images/providers/facebook.png -------------------------------------------------------------------------------- /public/images/providers/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datalek/silhouette-rest-seed/HEAD/public/images/providers/twitter.png -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | #Activator-generated Properties 2 | #Tue Jul 15 10:15:33 CEST 2014 3 | template.uuid=af582966-096a-43df-a504-5ddae8d4ebf1 4 | sbt.version=0.13.5 5 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/" 2 | 3 | // The Play plugin 4 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.1") 5 | -------------------------------------------------------------------------------- /app/modules/cake/UserServiceModule.scala: -------------------------------------------------------------------------------- 1 | package modules.cake 2 | 3 | import services.UserServiceInMemory 4 | 5 | /** 6 | * Provides the user service 7 | */ 8 | trait UserServiceModule { 9 | 10 | lazy val userService = new UserServiceInMemory 11 | 12 | } -------------------------------------------------------------------------------- /app/views/authentication/mails/welcomeEmail.scala.html: -------------------------------------------------------------------------------- 1 | @(user: models.users.User)(implicit request: RequestHeader, lang: Lang) 2 | 3 |
4 |Welcome @user.info.fullName.getOrElse("???"),
5 |
6 | Your new account is ready!!
7 |
8 |
--------------------------------------------------------------------------------
/app/models/users/BaseInfo.scala:
--------------------------------------------------------------------------------
1 | package models.users
2 |
3 | /**
4 | * Base info of an user
5 | */
6 | case class BaseInfo(
7 | firstName: Option[String],
8 | lastName: Option[String],
9 | fullName: Option[String],
10 | gender: Option[String]) {
11 |
12 | }
--------------------------------------------------------------------------------
/app/security/models/SignUp.scala:
--------------------------------------------------------------------------------
1 | package security.models
2 |
3 | /**
4 | * Case class for signUp element
5 | */
6 | case class SignUp(
7 | password: String,
8 | identifier: String,
9 | firstName: Option[String],
10 | lastName: Option[String],
11 | fullName: Option[String])
--------------------------------------------------------------------------------
/app/security/formatters/json/OAuth1InfoFormats.scala:
--------------------------------------------------------------------------------
1 | package security.formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.impl.providers.OAuth1Info
6 |
7 | object OAuth1InfoFormats {
8 |
9 | implicit val restFormat = (
10 | (__ \ "token").format[String] ~
11 | (__ \ "secret").format[String])(OAuth1Info.apply, unlift(OAuth1Info.unapply))
12 | }
--------------------------------------------------------------------------------
/app/modules/cake/AvatarServiceModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import com.mohiva.play.silhouette.impl.services._
4 | import com.mohiva.play.silhouette.api.util.HTTPLayer
5 |
6 | /**
7 | * Provides the avatar service.
8 | *
9 | * @param httpLayer The HTTP layer implementation.
10 | */
11 | trait AvatarServiceModule {
12 |
13 | def httpLayer: HTTPLayer
14 |
15 | lazy val avatarService = new GravatarService(httpLayer)
16 |
17 | }
--------------------------------------------------------------------------------
/app/formatters/json/CredentialFormat.scala:
--------------------------------------------------------------------------------
1 | package formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.util.Credentials
6 |
7 | /**
8 | *
9 | */
10 | object CredentialFormat {
11 |
12 | implicit val restFormat = (
13 | (__ \ "identifier").format[String] ~
14 | (__ \ "password").format[String])(Credentials.apply, unlift(Credentials.unapply))
15 |
16 | }
--------------------------------------------------------------------------------
/public/stylesheets/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
4 | h1 {
5 | text-align: center;
6 | font-size: 30px;
7 | }
8 | .starter-template {
9 | padding: 40px 15px;
10 | }
11 |
12 | fieldset {
13 | margin-top: 100px;
14 | text-align: center;
15 | }
16 | .social-providers,
17 | .sign-in-now {
18 | margin-top: 20px;
19 | }
20 |
21 | .user {
22 | margin-top: 50px;
23 | }
24 | .user .data {
25 | margin-top: 10px;
26 | }
27 |
--------------------------------------------------------------------------------
/app/security/formatters/json/PasswordInfoFormats.scala:
--------------------------------------------------------------------------------
1 | package security.formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.util.PasswordInfo
6 |
7 | object PasswordInfoFormats {
8 |
9 | implicit val restFormat = (
10 | (__ \ "hasher").format[String] ~
11 | (__ \ "password").format[String] ~
12 | (__ \ "salt").formatNullable[String])(PasswordInfo.apply, unlift(PasswordInfo.unapply))
13 | }
--------------------------------------------------------------------------------
/app/security/formatters/json/CredentialFormats.scala:
--------------------------------------------------------------------------------
1 | package security.formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.util.Credentials
6 |
7 | /**
8 | * Contain all format for com.mohiva.play.silhouette.api.providers.Credentials type
9 | */
10 | object CredentialFormat {
11 |
12 | implicit val restFormat = (
13 | (__ \ "identifier").format[String] ~
14 | (__ \ "password").format[String])(Credentials.apply, unlift(Credentials.unapply))
15 |
16 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is licensed under the Apache 2 license, quoted below.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with
4 | the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
5 |
6 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
7 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
8 | language governing permissions and limitations under the License.
--------------------------------------------------------------------------------
/app/models/users/User.scala:
--------------------------------------------------------------------------------
1 | package models.users
2 |
3 | import com.mohiva.play.silhouette.api.Identity
4 | import com.mohiva.play.silhouette.api.LoginInfo
5 | import java.util.UUID
6 |
7 | import models.authorizations._
8 |
9 | /**
10 | * A user of this platform
11 | */
12 | case class User(
13 | id: String = UUID.randomUUID.toString,
14 | loginInfo: LoginInfo,
15 | socials: Option[Seq[LoginInfo]] = None,
16 | email: Option[String],
17 | username: Option[String],
18 | avatarUrl: Option[String],
19 | info: BaseInfo,
20 | roles: Set[Role] = Set(SimpleUser)) extends Identity {
21 |
22 | }
23 |
24 | object User {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/security/formatters/json/OAuth2InfoFormats.scala:
--------------------------------------------------------------------------------
1 | package security.formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import play.api.libs.json.Json.JsValueWrapper
6 | import com.mohiva.play.silhouette.impl.providers.OAuth2Info
7 |
8 | object OAuth2InfoFormats {
9 |
10 | implicit val restFormat = (
11 | (__ \ "accessToken").format[String] ~
12 | (__ \ "tokenType").formatNullable[String] ~
13 | (__ \ "expiresIn").formatNullable[Int] ~
14 | (__ \ "refreshToken").formatNullable[String] ~
15 | (__ \ "params").formatNullable[Map[String, String]])(OAuth2Info.apply, unlift(OAuth2Info.unapply))
16 | }
--------------------------------------------------------------------------------
/app/formatters/json/BaseInfoFormats.scala:
--------------------------------------------------------------------------------
1 | package formatters
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.LoginInfo
6 |
7 | import models.users.BaseInfo
8 |
9 | /**
10 | * This object contains all format for User class
11 | */
12 | object BaseInfoFormats {
13 |
14 | val storageFormat = (
15 | (__ \ "firstName").formatNullable[String] ~
16 | (__ \ "lastName").formatNullable[String] ~
17 | (__ \ "fullName").formatNullable[String] ~
18 | (__ \ "gender").formatNullable[String])(BaseInfo.apply _, unlift(BaseInfo.unapply _))
19 |
20 | val restFormat = storageFormat
21 |
22 | }
--------------------------------------------------------------------------------
/app/security/models/Token.scala:
--------------------------------------------------------------------------------
1 | package security.models
2 |
3 | import org.joda.time.DateTime
4 | import play.api.libs.json._
5 |
6 | /**
7 | * This class represent token
8 | *
9 | * @param token Id of token
10 | * @param expiresOn The expiration time
11 | */
12 | case class Token(token: String, expiresOn: DateTime)
13 |
14 | /**
15 | * Companion object, contain format for Json
16 | */
17 | object Token {
18 |
19 |
20 | implicit val jodaDateWrites: Writes[org.joda.time.DateTime] = new Writes[org.joda.time.DateTime] {
21 | def writes(d: org.joda.time.DateTime): JsValue = JsString(d.toString)
22 | }
23 |
24 | implicit val restFormat = Json.format[Token]
25 |
26 | }
--------------------------------------------------------------------------------
/app/formatters/json/SocialAuthFormat.scala:
--------------------------------------------------------------------------------
1 | package formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 |
6 | /**
7 | * Generic class for Rest Social authentication
8 | */
9 | case class SocialAuth(
10 | token: String,
11 | secret: Option[String])
12 |
13 | /**
14 | * Companion object
15 | */
16 | object SocialAuth {
17 | implicit val restFormat = SocialAuthFormat.restFormat
18 | }
19 |
20 | /**
21 | * Formatter for SocialAuth class
22 | */
23 | object SocialAuthFormat {
24 |
25 | implicit val restFormat = (
26 | (__ \ "token").format[String] ~
27 | (__ \ "secret").formatNullable[String])(SocialAuth.apply, unlift(SocialAuth.unapply))
28 |
29 | }
--------------------------------------------------------------------------------
/app/modules/cake/MailServiceModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import play.api.mvc.RequestHeader
4 | import play.api.i18n.Lang
5 | import services._
6 | import models.users._
7 |
8 | /**
9 | * Provides the mail service.
10 | *
11 | */
12 | trait MailServiceModule {
13 |
14 | class SimpleMailService extends MailService[User] {
15 |
16 | def sendWelcomeEmail(user: User)(implicit request: RequestHeader, lang: Lang) = {
17 | val html = views.html.authentication.mails.welcomeEmail(user)(request, lang)
18 | val txtAndHtml = (None, Some(html))
19 | sendEmail("Welcome!!!!", user.email.get, txtAndHtml)
20 | }
21 |
22 | }
23 |
24 | lazy val mailService = new SimpleMailService
25 |
26 | }
--------------------------------------------------------------------------------
/app/modules/cake/CredentialsProviderModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import com.mohiva.play.silhouette.impl.providers.CredentialsProvider
4 | import com.mohiva.play.silhouette.api.services.AuthInfoService
5 | import com.mohiva.play.silhouette.api.util.PasswordHasher
6 |
7 | /**
8 | * Provides the credentials provider.
9 | *
10 | * @param authInfoService The auth info service implemenetation.
11 | * @param passwordHasher The default password hasher implementation.
12 | */
13 | trait CredentialsProviderModule {
14 |
15 | def authInfoService: AuthInfoService
16 | def passwordHasher: PasswordHasher
17 |
18 | lazy val credentialsProvider = new CredentialsProvider(authInfoService, passwordHasher, Seq(passwordHasher))
19 |
20 | }
--------------------------------------------------------------------------------
/app/security/models/SocialAuth.scala:
--------------------------------------------------------------------------------
1 | package security.models
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.util.Credentials
6 |
7 | /**
8 | * Generic class for Rest Social authentication
9 | */
10 | case class SocialAuth(
11 | token: String,
12 | expiresIn: Option[Int],
13 | secret: Option[String])
14 |
15 | /**
16 | * Companion object
17 | */
18 | object SocialAuth {
19 | implicit val restFormat = SocialAuthFormat.restFormat
20 | }
21 |
22 | /**
23 | * Formatter for SocialAuth class
24 | */
25 | object SocialAuthFormat {
26 |
27 | implicit val restFormat = (
28 | (__ \ "accessToken").format[String] ~
29 | (__ \ "expiresIn").formatNullable[Int] ~
30 | (__ \ "secret").formatNullable[String])(SocialAuth.apply, unlift(SocialAuth.unapply))
31 |
32 | }
--------------------------------------------------------------------------------
/conf/routes:
--------------------------------------------------------------------------------
1 | # Routes
2 | # This file defines all application routes (Higher priority routes first)
3 | # ~~~~
4 |
5 | GET / controllers.RestApplicationController.index
6 | GET /onlygodoruser controllers.RestApplicationController.onlyGodOrUser
7 |
8 | # Login/SignUp
9 | POST /auth/signin/credentials controllers.security.rest.RestCredentialsAuthController.authenticate
10 | POST /auth/signin/:provider controllers.security.rest.RestSocialAuthController.authenticate(provider)
11 | POST /auth/link/:provider controllers.security.rest.RestSocialAuthController.link(provider)
12 | POST /auth/signup controllers.security.rest.RestSignUpController.signUp
13 | GET /auth/signout controllers.security.rest.RestSignUpController.signOut
14 |
15 | # Map static resources from the /public folder to the /assets URL path
16 | GET /assets/*file controllers.Assets.at(path="/public", file)
--------------------------------------------------------------------------------
/app/modules/cake/AuthInfoServiceModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import com.mohiva.play.silhouette.impl.daos.DelegableAuthInfoDAO
4 | import com.mohiva.play.silhouette.impl.services.DelegableAuthInfoService
5 | import com.mohiva.play.silhouette.api.util.PasswordInfo
6 | import com.mohiva.play.silhouette.impl.providers.OAuth1Info
7 | import com.mohiva.play.silhouette.impl.providers.OAuth2Info
8 |
9 | /**
10 | * Provides the auth info service.
11 | *
12 | * @param passwordInfoDAO The implementation of the delegable password auth info DAO.
13 | * @param oauth1InfoDAO The implementation of the delegable OAuth1 auth info DAO.
14 | * @param oauth2InfoDAO The implementation of the delegable OAuth2 auth info DAO.
15 | */
16 | trait AuthInfoServiceModule {
17 |
18 | def passwordInfoDAO: DelegableAuthInfoDAO[PasswordInfo]
19 | def oauth1InfoDAO: DelegableAuthInfoDAO[OAuth1Info]
20 | def oauth2InfoDAO: DelegableAuthInfoDAO[OAuth2Info]
21 |
22 | lazy val authInfoService = new DelegableAuthInfoService(passwordInfoDAO, oauth1InfoDAO, oauth2InfoDAO)
23 |
24 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### OSX ###
4 | .DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 |
12 | ### Scala ###
13 | *.class
14 | *.log
15 |
16 | # sbt specific
17 | .cache
18 | .history
19 | .lib/
20 | dist/*
21 | target/
22 | lib_managed/
23 | src_managed/
24 | project/boot/
25 | project/plugins/project/
26 |
27 | # Scala-IDE specific
28 | .scala_dependencies
29 | .worksheet
30 |
31 |
32 | ### SBT ###
33 | # Simple Build Tool
34 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
35 |
36 | target/
37 | lib_managed/
38 | src_managed/
39 | project/boot/
40 | .history
41 | .cache
42 |
43 |
44 | ### PlayFramework ###
45 | # Ignore Play! working directory #
46 | bin/
47 | /db
48 | .eclipse
49 | /lib/
50 | /logs/
51 | /modules
52 | /project/project
53 | /project/target
54 | /target
55 | tmp/
56 | test-result
57 | server.pid
58 | *.iml
59 | *.eml
60 | /dist/
61 | .cache
62 |
63 |
64 | /.classpath
65 | /.project
66 | /.settings
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/utils/responses/rest/Good.scala:
--------------------------------------------------------------------------------
1 | package utils.responses.rest
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 |
6 | /**
7 | * An util class, represent a good response, it's all right
8 | *
9 | * @param message
10 | */
11 | class Good(val message: JsValue) {
12 | def status = "ok"
13 | }
14 |
15 | /**
16 | * Companion object for Good class
17 | */
18 | object Good {
19 |
20 | def apply(message: String) = new Good(JsString(message))
21 | def apply(message: JsValue) = new Good(message)
22 | def unapply(good: Good) = Some((good.status, good.message))
23 |
24 | /**
25 | * Rest format
26 | */
27 | implicit val restFormat: Format[Good] = {
28 | /** because of single value of read, i have to do map, it's a bug of play's json library, but don't worry ;)*/
29 | val reads: Reads[Good] = (
30 | (__ \ "message").read[JsValue]).map(m => Good.apply(m))
31 |
32 | import play.api.libs.json.Writes._
33 | val writes: Writes[Good] = (
34 | (__ \ "status").write[String] ~
35 | (__ \ "message").write[JsValue])(unlift(Good.unapply _))
36 |
37 | Format(reads, writes)
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/app/utils/responses/rest/Bad.scala:
--------------------------------------------------------------------------------
1 | package utils.responses.rest
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 |
6 | /**
7 | * An util class, represent a bad response, not good
8 | *
9 | * @param code of error
10 | * @param error an object that expone the errors
11 | */
12 | class Bad(val code: Option[Int], val error: JsValue) {
13 | def status = "ko"
14 | }
15 |
16 | /**
17 | * Companion object for Good class
18 | */
19 | object Bad {
20 |
21 | def apply(code: Option[Int] = None, message: String) = new Bad(code, JsString(message))
22 | def apply(code: Option[Int], message: JsValue) = new Bad(code, message)
23 | def apply(message: JsValue) = new Bad(None, message)
24 | def unapply(bad: Bad) = Some((bad.status, bad.code, bad.error))
25 |
26 | /**
27 | * Rest format
28 | */
29 | implicit val restFormat: Format[Bad] = {
30 | val reader: Reads[Bad] = (
31 | (__ \ "code").readNullable[Int] ~
32 | (__ \ "error").read[JsValue])(Bad.apply(_, _))
33 |
34 | val writer: Writes[Bad] = (
35 | (__ \ "status").write[String] ~
36 | (__ \ "code").writeNullable[Int] ~
37 | (__ \ "error").write[JsValue])(unlift(Bad.unapply _))
38 |
39 | Format(reader, writer)
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/app/models/authorizations/Roles.scala:
--------------------------------------------------------------------------------
1 | package models.authorizations
2 |
3 | import com.mohiva.play.silhouette.api.Authorization
4 | import models.users._
5 | import play.api.i18n._
6 | import play.api.mvc.RequestHeader
7 |
8 | /**
9 | * Check for authorization
10 | */
11 | case class WithRole(role: Role) extends Authorization[User] {
12 | def isAuthorized(user: User)(implicit request: RequestHeader, lang: Lang) = user.roles match {
13 | case list: Set[Role] => list.contains(role)
14 | case _ => false
15 | }
16 |
17 | }
18 | /**
19 | * Trait for all roles
20 | */
21 | trait Role {
22 | def name: String
23 | }
24 |
25 | /**
26 | * Companion object
27 | */
28 | object Role {
29 |
30 | def apply(role: String): Role = role match {
31 | case God.name => God
32 | case Admin.name => Admin
33 | case SimpleUser.name => SimpleUser
34 | case _ => Unknown
35 | }
36 |
37 | def unapply(role: Role): Option[String] = Some(role.name)
38 |
39 | }
40 |
41 | /**
42 | * Administration role
43 | */
44 | object God extends Role {
45 | val name = "god"
46 | }
47 |
48 | /**
49 | * Administration role
50 | */
51 | object Admin extends Role {
52 | val name = "admin"
53 | }
54 |
55 | /**
56 | * Normal user role
57 | */
58 | object SimpleUser extends Role {
59 | val name = "user"
60 | }
61 |
62 | /**
63 | * The generic unknown role
64 | */
65 | object Unknown extends Role {
66 | val name = "-"
67 | }
--------------------------------------------------------------------------------
/conf/silhouette.conf:
--------------------------------------------------------------------------------
1 | silhouette {
2 |
3 | # Authenticator settings
4 | authenticator.cookieName="id"
5 | authenticator.cookiePath="/"
6 | authenticator.secureCookie=false
7 | authenticator.httpOnlyCookie=true
8 | authenticator.authenticatorIdleTimeout=1800
9 | authenticator.cookieAbsoluteTimeout=43200
10 | authenticator.authenticatorExpiry=43200
11 | #authenticator.headerName="Authenticate"
12 |
13 | # Facebook provider
14 | facebook.authorizationURL="https://graph.facebook.com/oauth/authorize"
15 | facebook.accessTokenURL="https://graph.facebook.com/oauth/access_token"
16 | facebook.redirectURL="http://localhost:9000/authenticate/facebook"
17 | facebook.clientID=""
18 | facebook.clientSecret=""
19 | facebook.scope="email"
20 |
21 | # Google provider
22 | google.authorizationURL="https://accounts.google.com/o/oauth2/auth"
23 | google.accessTokenURL="https://accounts.google.com/o/oauth2/token"
24 | google.redirectURL="http://localhost:9000/authenticate/google"
25 | google.clientID=""
26 | google.clientSecret=""
27 | google.scope="profile email"
28 |
29 | # Twitter provider
30 | twitter.requestTokenURL="https://twitter.com/oauth/request_token"
31 | twitter.accessTokenURL="https://twitter.com/oauth/access_token"
32 | twitter.authorizationURL="https://twitter.com/oauth/authenticate"
33 | twitter.callbackURL="http://localhost:9000/authenticate/twitter"
34 | twitter.consumerKey=""
35 | twitter.consumerSecret=""
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/formatters/json/UserFormats.scala:
--------------------------------------------------------------------------------
1 | package formatters.json
2 |
3 | import play.api.libs.json._
4 | import play.api.libs.functional.syntax._
5 | import com.mohiva.play.silhouette.api.LoginInfo
6 | import models.authorizations._
7 | import models.users._
8 |
9 | /**
10 | * This object contains all format for User class
11 | */
12 | object UserFormats {
13 |
14 | val restFormat = {
15 | implicit val baseInfoFormat = formatters.BaseInfoFormats.restFormat
16 |
17 | val reader = (
18 | (__ \ "id").read[String] ~
19 | (__ \ "loginInfo").read[LoginInfo] ~
20 | (__ \ "socials").readNullable(Reads.seq[LoginInfo]) ~
21 | (__ \ "email").readNullable(Reads.email) ~
22 | (__ \ "username").readNullable[String] ~
23 | (__ \ "avatarUrl").readNullable[String] ~
24 | (__ \ "info").read[BaseInfo] ~
25 | (__ \ "roles").readNullable(Reads.set[String]).map { case Some(r) => r.map(Role.apply) case None => Set[Role](SimpleUser) })(User.apply _)
26 |
27 | val writer = (
28 | (__ \ "id").write[String] ~
29 | (__ \ "loginInfo").write[LoginInfo] ~
30 | (__ \ "socials").writeNullable(Writes.seq[LoginInfo]) ~
31 | (__ \ "email").writeNullable[String] ~
32 | (__ \ "username").writeNullable[String] ~
33 | (__ \ "avatarUrl").writeNullable[String] ~
34 | (__ \ "info").write[BaseInfo] ~
35 | (__ \ "roles").write(Writes.set[String]).contramap[Set[Role]](_.map(_.name)))(unlift(User.unapply _))
36 |
37 | Format(reader, writer)
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/controllers/RestApplicationController.scala:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import play.api.libs.json._
4 | import scala.concurrent.Future
5 | import play.api.libs.concurrent.Execution.Implicits._
6 | import models.users.User
7 | import com.mohiva.play.silhouette.impl.authenticators.JWTAuthenticator
8 | import com.mohiva.play.silhouette.api.Silhouette
9 | import modules.cake.HeaderEnvironmentModule
10 | import models.authorizations._
11 |
12 |
13 | import utils.responses.rest._
14 |
15 | /**
16 | * The basic application controller.
17 | *
18 | * @param env The Silhouette environment.
19 | */
20 | class RestApplicationController extends Silhouette[User, JWTAuthenticator] with HeaderEnvironmentModule {
21 |
22 | implicit val userFormat = formatters.json.UserFormats.restFormat
23 |
24 | /**
25 | * Handles the index action.
26 | *
27 | * @return The result to display.
28 | */
29 | def index = UserAwareAction.async { implicit request =>
30 | request.identity match {
31 | case Some(user) => Future.successful(Ok(Json.toJson(user)))
32 | case None => Future.successful(Ok(Json.toJson(Good(message = "you are not logged! Login man!"))))
33 | }
34 | }
35 |
36 | /**
37 | * Handles the index action.
38 | *
39 | * @return The result to display.
40 | */
41 | def onlyGodOrUser = SecuredAction(WithRole(God) || WithRole(SimpleUser)).async { implicit request =>
42 | Future.successful(Ok(Json.obj("result" -> "Oh yess GOD")))
43 | }
44 |
45 | }
46 |
47 | object RestApplicationController extends RestApplicationController
--------------------------------------------------------------------------------
/app/models/daos/OAuth1InfoDAO.scala:
--------------------------------------------------------------------------------
1 | package models.daos
2 |
3 | import com.mohiva.play.silhouette.api.LoginInfo
4 | import com.mohiva.play.silhouette.impl.providers.OAuth1Info
5 | import com.mohiva.play.silhouette.impl.daos.DelegableAuthInfoDAO
6 | import scala.collection.mutable
7 | import scala.concurrent.Future
8 | import OAuth1InfoDAO._
9 |
10 | /**
11 | * The DAO to store the OAuth1 information.
12 | */
13 | class OAuth1InfoDAO extends DelegableAuthInfoDAO[OAuth1Info] {
14 |
15 | /**
16 | * Saves the OAuth1 info.
17 | *
18 | * @param loginInfo The login info for which the auth info should be saved.
19 | * @param authInfo The OAuth1 info to save.
20 | * @return The saved OAuth1 info or None if the OAuth1 info couldn't be saved.
21 | */
22 | def save(loginInfo: LoginInfo, authInfo: OAuth1Info): Future[OAuth1Info] = {
23 | data += (loginInfo -> authInfo)
24 | Future.successful(authInfo)
25 | }
26 |
27 | /**
28 | * Finds the OAuth1 info which is linked with the specified login info.
29 | *
30 | * @param loginInfo The linked login info.
31 | * @return The retrieved OAuth1 info or None if no OAuth1 info could be retrieved for the given login info.
32 | */
33 | def find(loginInfo: LoginInfo): Future[Option[OAuth1Info]] = {
34 | Future.successful(data.get(loginInfo))
35 | }
36 | }
37 |
38 | /**
39 | * The companion object.
40 | */
41 | object OAuth1InfoDAO {
42 |
43 | /**
44 | * The data store for the OAuth1 info.
45 | */
46 | var data: mutable.HashMap[LoginInfo, OAuth1Info] = mutable.HashMap()
47 | }
48 |
--------------------------------------------------------------------------------
/app/models/daos/OAuth2InfoDAO.scala:
--------------------------------------------------------------------------------
1 | package models.daos
2 |
3 | import com.mohiva.play.silhouette.api.LoginInfo
4 | import com.mohiva.play.silhouette.impl.providers.OAuth2Info
5 | import com.mohiva.play.silhouette.impl.daos.DelegableAuthInfoDAO
6 | import scala.collection.mutable
7 | import scala.concurrent.Future
8 | import OAuth2InfoDAO._
9 |
10 | /**
11 | * The DAO to store the OAuth2 information.
12 | */
13 | class OAuth2InfoDAO extends DelegableAuthInfoDAO[OAuth2Info] {
14 |
15 | /**
16 | * Saves the OAuth2 info.
17 | *
18 | * @param loginInfo The login info for which the auth info should be saved.
19 | * @param authInfo The OAuth2 info to save.
20 | * @return The saved OAuth2 info or None if the OAuth2 info couldn't be saved.
21 | */
22 | def save(loginInfo: LoginInfo, authInfo: OAuth2Info): Future[OAuth2Info] = {
23 | data += (loginInfo -> authInfo)
24 | Future.successful(authInfo)
25 | }
26 |
27 | /**
28 | * Finds the OAuth2 info which is linked with the specified login info.
29 | *
30 | * @param loginInfo The linked login info.
31 | * @return The retrieved OAuth2 info or None if no OAuth2 info could be retrieved for the given login info.
32 | */
33 | def find(loginInfo: LoginInfo): Future[Option[OAuth2Info]] = {
34 | Future.successful(data.get(loginInfo))
35 | }
36 | }
37 |
38 | /**
39 | * The companion object.
40 | */
41 | object OAuth2InfoDAO {
42 |
43 | /**
44 | * The data store for the OAuth2 info.
45 | */
46 | var data: mutable.HashMap[LoginInfo, OAuth2Info] = mutable.HashMap()
47 | }
48 |
--------------------------------------------------------------------------------
/app/models/daos/PasswordInfoDAO.scala:
--------------------------------------------------------------------------------
1 | package models.daos
2 |
3 | import com.mohiva.play.silhouette.api.LoginInfo
4 | import com.mohiva.play.silhouette.api.util.PasswordInfo
5 | import com.mohiva.play.silhouette.impl.daos.DelegableAuthInfoDAO
6 | import scala.collection.mutable
7 | import scala.concurrent.Future
8 | import PasswordInfoDAO._
9 |
10 | /**
11 | * The DAO to store the password information.
12 | */
13 | class PasswordInfoDAO extends DelegableAuthInfoDAO[PasswordInfo] {
14 |
15 | /**
16 | * Saves the password info.
17 | *
18 | * @param loginInfo The login info for which the auth info should be saved.
19 | * @param authInfo The password info to save.
20 | * @return The saved password info or None if the password info couldn't be saved.
21 | */
22 | def save(loginInfo: LoginInfo, authInfo: PasswordInfo): Future[PasswordInfo] = {
23 | data += (loginInfo -> authInfo)
24 | Future.successful(authInfo)
25 | }
26 |
27 | /**
28 | * Finds the password info which is linked with the specified login info.
29 | *
30 | * @param loginInfo The linked login info.
31 | * @return The retrieved password info or None if no password info could be retrieved for the given login info.
32 | */
33 | def find(loginInfo: LoginInfo): Future[Option[PasswordInfo]] = {
34 | play.Logger.debug(s"data: ${data}")
35 | Future.successful(data.get(loginInfo))
36 | }
37 | }
38 |
39 | /**
40 | * The companion object.
41 | */
42 | object PasswordInfoDAO {
43 |
44 | /**
45 | * The data store for the password info.
46 | */
47 | var data: mutable.HashMap[LoginInfo, PasswordInfo] = mutable.HashMap()
48 | }
--------------------------------------------------------------------------------
/app/services/MailService.scala:
--------------------------------------------------------------------------------
1 | package services
2 |
3 | import play.api.libs.concurrent.Akka
4 | import play.api.Play.current
5 | import play.api.mvc.RequestHeader
6 | import play.api.i18n.Lang
7 | import play.twirl.api.{ Txt, Html }
8 | import com.typesafe.plugin._
9 | import scala.concurrent.duration._
10 | import play.api.libs.concurrent.Execution.Implicits._
11 | import akka.actor._
12 | import com.mohiva.play.silhouette.api._
13 |
14 | /**
15 | *
16 | */
17 | trait MailService[I <: Identity] {
18 |
19 | /**
20 | *
21 | */
22 | val fromAddress = current.configuration.getString("smtp.from").get
23 |
24 | def sendWelcomeEmail(user: I)(implicit request: RequestHeader, lang: Lang)
25 |
26 | // def sendPasswordResetEmail(user: I, token: String)(implicit request: RequestHeader, lang: Lang)
27 | //
28 | // def sendPasswordChangedNotice(user: I)(implicit request: RequestHeader, lang: Lang)
29 |
30 | /**
31 | * @param subject of the email
32 | * @param recipient of the email
33 | * @param body pair with Text and Html email
34 | */
35 | def sendEmail(subject: String, recipient: String, body: (Option[Txt], Option[Html])) = {
36 |
37 | play.Logger.debug(s"[securesocial] sending email to $recipient")
38 | play.Logger.debug(s"[securesocial] mail = [$body]")
39 |
40 | Akka.system.scheduler.scheduleOnce(1 seconds) {
41 | val mail = use[MailerPlugin].email
42 | mail.setSubject(subject)
43 | mail.setRecipient(recipient)
44 | mail.setFrom(fromAddress)
45 | // the mailer plugin handles null / empty string gracefully
46 | mail.send(body._1.map(_.body).getOrElse(""), body._2.map(_.body).getOrElse(""))
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/app/services/UserService.scala:
--------------------------------------------------------------------------------
1 | package services
2 |
3 | import scala.concurrent.Future
4 | import play.api.libs.json.{JsValue, JsNull}
5 | import com.mohiva.play.silhouette.api.LoginInfo
6 | import com.mohiva.play.silhouette.api.services.{ AuthInfo, IdentityService }
7 | import com.mohiva.play.silhouette.impl.providers.CommonSocialProfile
8 |
9 | import security.models.SignUp
10 | import models.users.User
11 |
12 | /**
13 | * Handles actions to users.
14 | */
15 | trait UserService extends IdentityService[User] {
16 |
17 | /**
18 | * Create a user from login information and signup information
19 | *
20 | * @param loginInfo The information about login
21 | * @param signUp The information about User
22 | * @param avatarUrl string with url to avatar image
23 | * @param json all json with signup information
24 | */
25 | def create(loginInfo: LoginInfo, signUp: SignUp, avatarUrl: Option[String] = None, json: JsValue = JsNull): Future[User]
26 |
27 | /**
28 | * Saves a user.
29 | *
30 | * @param user The user to save.
31 | * @return The saved user.
32 | */
33 | def save(user: User): Future[User]
34 |
35 | /**
36 | * Saves the social profile for a user.
37 | *
38 | * If a user exists for this profile then update the user, otherwise create a new user with the given profile.
39 | *
40 | * @param profile The social profile to save.
41 | * @return The user for whom the profile was saved.
42 | */
43 | def save[A <: AuthInfo](profile: CommonSocialProfile): Future[User]
44 |
45 | /**
46 | * Link a social social profile on a user.
47 | *
48 | *
49 | * @param profile The social profile to save.
50 | * @return The user for whom the profile was saved.
51 | */
52 | def link[A <: AuthInfo](user: User, profile: CommonSocialProfile): Future[User]
53 | }
--------------------------------------------------------------------------------
/app/modules/cake/AuthenticatorServiceModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import play.api.Play
4 | import play.api.Play.current
5 | /** mohiva module import */
6 | import com.mohiva.play.silhouette.impl.authenticators._
7 | import com.mohiva.play.silhouette.api.services.AuthenticatorService
8 | import com.mohiva.play.silhouette.api.util.CacheLayer
9 | import com.mohiva.play.silhouette.api.util.Clock
10 | import com.mohiva.play.silhouette.api.util.IDGenerator
11 |
12 | /**
13 | * Provides the Header authenticator service.
14 | *
15 | * @param cacheLayer The cache layer implementation.
16 | * @param idGenerator The ID generator used to create the authenticator ID.
17 | */
18 | trait HeaderAuthenticatorServiceModule {
19 |
20 | def idGenerator: IDGenerator
21 |
22 | lazy val authenticatorService: AuthenticatorService[JWTAuthenticator] = {
23 | val settings = JWTAuthenticatorSettings(
24 | headerName = Play.configuration.getString("silhouette.authenticator.headerName").getOrElse { "X-Auth-Token" },
25 | issuerClaim = Play.configuration.getString("silhouette.authenticator.issueClaim").getOrElse { "play-silhouette" },
26 | encryptSubject = Play.configuration.getBoolean("silhouette.authenticator.encryptSubject").getOrElse { true },
27 | authenticatorIdleTimeout = Play.configuration.getInt("silhouette.authenticator.authenticatorIdleTimeout"), // This feature is disabled by default to prevent the generation of a new JWT on every request
28 | authenticatorExpiry = Play.configuration.getInt("silhouette.authenticator.authenticatorExpiry").getOrElse { 12 * 60 * 60 },
29 | sharedSecret = Play.configuration.getString("application.secret").get)
30 | new JWTAuthenticatorService(
31 | settings = settings,
32 | dao = None,
33 | idGenerator = idGenerator,
34 | clock = Clock())
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/app/modules/cake/EnvironmentModule.scala:
--------------------------------------------------------------------------------
1 | package modules.cake
2 |
3 | import com.mohiva.play.silhouette.impl.authenticators.{ CookieAuthenticator, JWTAuthenticator }
4 | import com.mohiva.play.silhouette.impl.util.BCryptPasswordHasher
5 | import com.mohiva.play.silhouette.impl.util.PlayCacheLayer
6 | import com.mohiva.play.silhouette.impl.util.SecureRandomIDGenerator
7 | import com.mohiva.play.silhouette.api.Environment
8 | import com.mohiva.play.silhouette.api.EventBus
9 | import com.mohiva.play.silhouette.api.util.PlayHTTPLayer
10 | import models.users.User
11 | import models.daos._
12 |
13 |
14 | /**
15 | * Provides the Silhouette environment.
16 | *
17 | * @param userService The user service implementation.
18 | * @param authenticatorService The authentication service implementation.
19 | * @param eventBus The event bus instance.
20 | */
21 | trait HeaderEnvironmentModule
22 | extends HeaderAuthenticatorServiceModule
23 | with UserServiceModule
24 | with AuthInfoServiceModule
25 | with CredentialsProviderModule
26 | with SocialProviderModule
27 | with MailServiceModule {
28 |
29 | /**
30 | * Configures the module.
31 | */
32 | lazy val cacheLayer = new PlayCacheLayer
33 | lazy val httpLayer = new PlayHTTPLayer
34 | lazy val eventBus = EventBus()
35 | lazy val idGenerator = new SecureRandomIDGenerator
36 | lazy val passwordInfoDAO = new PasswordInfoDAO
37 | lazy val oauth1InfoDAO = new OAuth1InfoDAO
38 | lazy val oauth2InfoDAO = new OAuth2InfoDAO
39 | lazy val passwordHasher = new BCryptPasswordHasher
40 |
41 | implicit lazy val env: Environment[User, JWTAuthenticator] = {
42 | Environment[User, JWTAuthenticator](
43 | userService,
44 | authenticatorService,
45 | Map(
46 | credentialsProvider.id -> credentialsProvider,
47 | facebookProvider.id -> facebookProvider),
48 | eventBus)
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/conf/application.conf:
--------------------------------------------------------------------------------
1 | # This is the main configuration file for the application.
2 | # ~~~~~
3 |
4 | # Secret key
5 | # ~~~~~
6 | # The secret key is used to secure cryptographics functions.
7 | #
8 | # This must be changed for production, but we recommend not changing it in this file.
9 | #
10 | # See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
11 | application.secret="52KF8WYk