├── .coveralls.yml ├── project ├── build.properties ├── build-jvm-opts ├── plugins.sbt └── Dependencies.scala ├── site └── CNAME ├── scripts ├── api-doc.key.enc ├── reformat ├── sbt ├── coveralls ├── ci-build ├── validate-format └── api-doc ├── silhouette ├── test │ ├── resources │ │ └── providers │ │ │ ├── oauth2 │ │ │ ├── gitlab.error.json │ │ │ ├── dropbox.error.json │ │ │ ├── foursquare.access.token.json │ │ │ ├── linkedin.access.token.json │ │ │ ├── github.error.json │ │ │ ├── dropbox.access.token.json │ │ │ ├── github.access.token.json │ │ │ ├── gitlab.access.token.json │ │ │ ├── google.access.token.json │ │ │ ├── facebook.access.token.json │ │ │ ├── vk.access.token.json │ │ │ ├── instagram.error.json │ │ │ ├── vk.success.without.photo.json │ │ │ ├── foursquare.error.json │ │ │ ├── github.success.json │ │ │ ├── facebook.error.json │ │ │ ├── dropbox.success.json │ │ │ ├── vk.success.json │ │ │ ├── vk.success.deprecated.json │ │ │ ├── instagram.success.json │ │ │ ├── linkedin.email.json │ │ │ ├── instagram.access.token.json │ │ │ ├── google.error.json │ │ │ ├── facebook.success.json │ │ │ ├── foursquare.success.json │ │ │ ├── foursquare.deprecated.json │ │ │ ├── vk.error.json │ │ │ ├── linkedin.success.json │ │ │ ├── google.error.api.missing.json │ │ │ ├── google.without.email.json │ │ │ ├── gitlab.success.json │ │ │ ├── google.success.json │ │ │ ├── google.img.non-default.json │ │ │ └── google.img.default.json │ │ │ ├── custom │ │ │ ├── auth0.error.json │ │ │ ├── facebook.error.json │ │ │ ├── auth0.success.json │ │ │ ├── facebook.success.json │ │ │ └── auth0.profile.json │ │ │ └── oauth1 │ │ │ ├── twitter.error.json │ │ │ ├── xing.error.json │ │ │ ├── linkedin.error.json │ │ │ ├── linkedin.success.json │ │ │ ├── xing.success.json │ │ │ ├── twitter.success.json │ │ │ └── twitter.with.email.json │ └── com │ │ └── mohiva │ │ └── play │ │ └── silhouette │ │ ├── api │ │ ├── util │ │ │ ├── ClockSpec.scala │ │ │ ├── PlayHTTPLayerSpec.scala │ │ │ └── JsonFormatsSpec.scala │ │ ├── crypto │ │ │ ├── HashSpec.scala │ │ │ └── Base64Spec.scala │ │ ├── AuthenticatorSpec.scala │ │ └── services │ │ │ └── AuthenticatorResultSpec.scala │ │ └── impl │ │ ├── providers │ │ ├── openid │ │ │ ├── service │ │ │ │ └── PlayOpenIDServiceSpec.scala │ │ │ ├── SteamProviderSpec.scala │ │ │ └── YahooProviderSpec.scala │ │ ├── PasswordProviderSpec.scala │ │ ├── SocialProviderRegistrySpec.scala │ │ └── state │ │ │ └── UserStateItemHandlerSpec.scala │ │ └── util │ │ ├── SecureRandomIDGeneratorSpec.scala │ │ ├── PlayCacheLayerSpec.scala │ │ └── DefaultFingerprintGeneratorSpec.scala ├── conf │ ├── messages │ └── reference.conf ├── app │ └── com │ │ └── mohiva │ │ └── play │ │ └── silhouette │ │ ├── package.scala │ │ ├── api │ │ ├── AuthInfo.scala │ │ ├── util │ │ │ ├── package.scala │ │ │ ├── Credentials.scala │ │ │ ├── ExecutionContextProvider.scala │ │ │ ├── Clock.scala │ │ │ ├── FingerprintGenerator.scala │ │ │ ├── JsonFormats.scala │ │ │ ├── IDGenerator.scala │ │ │ ├── CacheLayer.scala │ │ │ └── HTTPLayer.scala │ │ ├── exceptions │ │ │ ├── package.scala │ │ │ ├── SilhouetteException.scala │ │ │ ├── AuthenticatorException.scala │ │ │ ├── CryptoException.scala │ │ │ ├── ProviderException.scala │ │ │ ├── ConfigurationException.scala │ │ │ ├── NotAuthenticatedException.scala │ │ │ ├── AuthenticatorUpdateException.scala │ │ │ ├── NotAuthorizedException.scala │ │ │ ├── AuthenticatorRenewalException.scala │ │ │ ├── AuthenticatorCreationException.scala │ │ │ ├── AuthenticatorRetrievalException.scala │ │ │ ├── AuthenticatorDiscardingException.scala │ │ │ └── AuthenticatorInitializationException.scala │ │ ├── package.scala │ │ ├── repositories │ │ │ ├── package.scala │ │ │ ├── AuthenticatorRepository.scala │ │ │ └── AuthInfoRepository.scala │ │ ├── services │ │ │ ├── package.scala │ │ │ ├── AvatarService.scala │ │ │ └── IdentityService.scala │ │ ├── Logger.scala │ │ ├── Identity.scala │ │ ├── crypto │ │ │ ├── Signer.scala │ │ │ ├── Crypter.scala │ │ │ ├── Base64.scala │ │ │ ├── AuthenticatorEncoder.scala │ │ │ └── Hash.scala │ │ ├── LoginInfo.scala │ │ ├── Provider.scala │ │ ├── Silhouette.scala │ │ └── Environment.scala │ │ └── impl │ │ ├── package.scala │ │ ├── util │ │ ├── package.scala │ │ ├── PlayCacheLayer.scala │ │ ├── SecureRandomIDGenerator.scala │ │ └── DefaultFingerprintGenerator.scala │ │ ├── services │ │ └── package.scala │ │ ├── authenticators │ │ └── package.scala │ │ ├── exceptions │ │ ├── package.scala │ │ ├── OAuth2StateException.scala │ │ ├── AccessDeniedException.scala │ │ ├── IdentityNotFoundException.scala │ │ ├── OAuth1TokenSecretException.scala │ │ ├── InvalidPasswordException.scala │ │ ├── UnexpectedResponseException.scala │ │ └── ProfileRetrievalException.scala │ │ ├── providers │ │ ├── package.scala │ │ └── openid │ │ │ ├── services │ │ │ └── PlayOpenIDService.scala │ │ │ └── SteamProvider.scala │ │ └── User.scala ├── app-2.13- │ └── com │ │ └── mohiva │ │ └── play │ │ └── silhouette │ │ └── ScalaCompat.scala ├── app-2.13+ │ └── com │ │ └── mohiva │ │ └── play │ │ └── silhouette │ │ └── ScalaCompat.scala └── build.sbt ├── silhouette-totp └── build.sbt ├── silhouette-password-bcrypt ├── build.sbt └── src │ └── main │ └── scala │ └── com │ └── mohiva │ └── play │ └── silhouette │ └── password │ └── BCryptPasswordHasher.scala ├── silhouette-crypto-jca ├── build.sbt └── src │ └── test │ └── scala │ └── com │ └── mohiva │ └── play │ └── silhouette │ └── crypto │ ├── JcaCrypterSpec.scala │ └── JcaSignerSpec.scala ├── .gitignore ├── silhouette-persistence ├── build.sbt └── src │ ├── main │ └── scala │ │ └── com │ │ └── mohiva │ │ └── play │ │ └── silhouette │ │ └── persistence │ │ ├── daos │ │ ├── package.scala │ │ ├── DelegableAuthInfoDAO.scala │ │ ├── AuthInfoDAO.scala │ │ └── InMemoryAuthInfoDAO.scala │ │ └── repositories │ │ ├── package.scala │ │ └── CacheAuthenticatorRepository.scala │ └── test │ └── scala │ └── com │ └── mohiva │ └── play │ └── silhouette │ ├── test │ └── WaitPatience.scala │ └── persistence │ └── repositories │ └── CacheAuthenticatorRepositorySpec.scala ├── silhouette-cas └── build.sbt ├── silhouette-testkit ├── build.sbt └── app │ └── com │ └── mohiva │ └── play │ └── silhouette │ └── test │ └── package.scala ├── .editorconfig ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .travis.yml ├── README.md ├── CONTRIBUTING.md └── CHANGELOG.md /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.18 2 | -------------------------------------------------------------------------------- /site/CNAME: -------------------------------------------------------------------------------- 1 | api.silhouette-play.mohiva.com 2 | -------------------------------------------------------------------------------- /project/build-jvm-opts: -------------------------------------------------------------------------------- 1 | # JVM options for building. 2 | 3 | -Xms2048M 4 | -Xmx2048M 5 | -Xss6M 6 | -------------------------------------------------------------------------------- /scripts/api-doc.key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohiva/play-silhouette/HEAD/scripts/api-doc.key.enc -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/gitlab.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Bad credentials" 3 | } 4 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/dropbox.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Invalid OAuth request." 3 | } 4 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/foursquare.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token" 3 | } 4 | -------------------------------------------------------------------------------- /silhouette/conf/messages: -------------------------------------------------------------------------------- 1 | silhouette.not.authenticated = Authentication required 2 | silhouette.not.authorized = Not authorized 3 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/linkedin.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "expires_in": 5184000, 3 | "access_token": "my.access.token" 4 | } 5 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/custom/auth0.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "invalid_request", 3 | "error_description": "the connection was disabled" 4 | } 5 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/github.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Bad credentials", 3 | "documentation_url": "http://developer.github.com/v3" 4 | } 5 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/dropbox.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "token_type": "bearer", 4 | "uid": "12345" 5 | } 6 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/github.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "scope": "repo,gist", 4 | "token_type": "bearer" 5 | } 6 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/gitlab.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "token_type": "bearer", 4 | "expires_in": 7200 5 | } 6 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "expires_in": 5184000, 4 | "token_type": "Bearer" 5 | } 6 | -------------------------------------------------------------------------------- /silhouette-totp/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.googleAuth, 5 | Library.Play.specs2 % Test 6 | ) 7 | 8 | enablePlugins(Doc) 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/facebook.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "token_type": "bearer", 4 | "expires_in": 5183836 5 | } 6 | -------------------------------------------------------------------------------- /silhouette-password-bcrypt/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.jbcrypt, 5 | Library.Specs2.core % Test 6 | ) 7 | 8 | enablePlugins(Doc) 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/twitter.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "Bad Authentication data", 5 | "code": 215 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/xing.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_name": "INVALID_PARAMETERS", 3 | "message": "Invalid parameters (Limit must be a non-negative number.)" 4 | } 5 | -------------------------------------------------------------------------------- /silhouette-crypto-jca/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.Specs2.core % Test, 5 | Library.Specs2.matcherExtra % Test 6 | ) 7 | 8 | enablePlugins(Doc) 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/vk.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "expires_in": 43200, 4 | "user_id": 6492, 5 | "email": "apollonia.vanova@watchmen.com" 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | project/project 3 | target 4 | tmp 5 | dist 6 | /.idea 7 | /*.iml 8 | /out 9 | /.idea_modules 10 | /.classpath 11 | /.project 12 | /RUNNING_PID 13 | /.settings 14 | /.target 15 | /.cache 16 | *.DS_Store -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/linkedin.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "errorCode": 0, 3 | "message": "Unknown authentication scheme", 4 | "requestId": "LY860UAC5U", 5 | "status": 401, 6 | "timestamp": 1390421660154 7 | } 8 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/instagram.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "error_type": "OAuthAccessTokenException", 4 | "code": 400, 5 | "error_message": "The access_token provided is invalid." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/vk.success.without.photo.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": [ 3 | { 4 | "id": 66748, 5 | "first_name": "Apollonia", 6 | "last_name": "Vanova" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/foursquare.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "code": 400, 4 | "errorType": "param_error", 5 | "errorDetail": "Must provide a valid user ID or 'self.'" 6 | }, 7 | "response": { } 8 | } 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/github.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "avatar_url": "https://github.com/images/error/apollonia_vanova.gif", 4 | "name": "Apollonia Vanova", 5 | "email": "apollonia.vanova@watchmen.com" 6 | } 7 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/custom/facebook.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "message": "An active access token must be used to query information about the current user.", 4 | "type": "OAuthException", 5 | "code": 2500 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/facebook.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "message": "An active access token must be used to query information about the current user.", 4 | "type": "OAuthException", 5 | "code": 2500 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /silhouette-persistence/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.Specs2.core % Test, 5 | Library.Specs2.matcherExtra % Test, 6 | Library.Specs2.mock % Test, 7 | Library.scalaGuice % Test 8 | ) 9 | 10 | enablePlugins(Doc) 11 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/dropbox.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid": 12345678, 3 | "display_name": "Apollonia Vanova", 4 | "name_details": { 5 | "familiar_name": "Apollonia", 6 | "given_name": "Apollonia", 7 | "surname": "Vanova" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/vk.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": [ 3 | { 4 | "id": 66748, 5 | "first_name": "Apollonia", 6 | "last_name": "Vanova", 7 | "photo_max_orig": "http://vk.com/images/camera_b.gif" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/vk.success.deprecated.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": [ 3 | { 4 | "uid": 66748, 5 | "first_name": "Apollonia", 6 | "last_name": "Vanova", 7 | "photo": "http://vk.com/images/camera_b.gif" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/package.scala: -------------------------------------------------------------------------------- 1 | package com.mohiva.play 2 | 3 | /** 4 | * An authentication library for Play Framework applications that supports several authentication methods, 5 | * including OAuth1, OAuth2, OpenID, Credentials or custom authentication schemes. 6 | */ 7 | package object silhouette 8 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/instagram.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "code": 200 4 | }, 5 | "data": { 6 | "id": "1574083", 7 | "full_name": "Apollonia Vanova", 8 | "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/linkedin.email.json: -------------------------------------------------------------------------------- 1 | { 2 | "elements": [ 3 | { 4 | "handle": "urn:li:emailAddress:30919315", 5 | "type": "EMAIL", 6 | "handle~": { 7 | "emailAddress": "apollonia.vanova@watchmen.com" 8 | }, 9 | "primary": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /silhouette-cas/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.casClient, 5 | Library.casClientSupportSAML, 6 | Library.Play.specs2 % Test, 7 | Library.Specs2.matcherExtra % Test, 8 | Library.Specs2.mock % Test, 9 | Library.scalaGuice % Test 10 | ) 11 | 12 | enablePlugins(Doc) 13 | -------------------------------------------------------------------------------- /silhouette-testkit/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.Play.test, 5 | Library.Play.specs2 % Test, 6 | Library.Specs2.matcherExtra % Test, 7 | Library.Specs2.mock % Test, 8 | Library.scalaGuice % Test, 9 | Library.akkaTestkit % Test 10 | ) 11 | 12 | enablePlugins(PlayScala, Doc) 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/instagram.access.token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "my.access.token", 3 | "user": { 4 | "id": "1574083", 5 | "username": "apollonia.vanova", 6 | "full_name": "Apollonia Vanova", 7 | "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/linkedin.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "NhZXBl_O6f", 3 | "firstName": "Apollonia", 4 | "lastName": "Vanova", 5 | "pictureUrl": "http://media.linkedin.com/mpr/mprx/0_fsPnURNRhLhk_Ue2fjKLUZkB2FL6TOe2S4bdUZz61GA9Ysxu_y_sz4THGW5JGJWhaMleN0F61-Dg", 6 | "formattedName": "Apollonia Vanova", 7 | "emailAddress": "apollonia.vanova@watchmen.com" 8 | } 9 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "errors": [ 4 | { 5 | "domain": "global", 6 | "reason": "authError", 7 | "message": "Invalid Credentials", 8 | "locationType": "header", 9 | "location": "Authorization" 10 | } 11 | ], 12 | "code": 401, 13 | "message": "Invalid Credentials" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/facebook.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "134405962728980", 3 | "name": "Apollonia Vanova", 4 | "first_name": "Apollonia", 5 | "last_name": "Vanova", 6 | "email": "apollonia.vanova@watchmen.com", 7 | "picture": { 8 | "data": { 9 | "url": "https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-ash2/t1/36245_155530314499277_2350717_n.jpg?lvh=1" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /silhouette/app-2.13-/com/mohiva/play/silhouette/ScalaCompat.scala: -------------------------------------------------------------------------------- 1 | package com.mohiva.play.silhouette 2 | 3 | import scala.collection.immutable.Map 4 | 5 | private[silhouette] object ScalaCompat { 6 | 7 | implicit class MapOps[K, V](val map: Map[K, V]) extends AnyVal { 8 | def transformValues[W](f: V => W): Map[K, W] = map.mapValues(f) 9 | } 10 | 11 | val JavaConverters = scala.collection.JavaConverters 12 | } 13 | -------------------------------------------------------------------------------- /silhouette/app-2.13+/com/mohiva/play/silhouette/ScalaCompat.scala: -------------------------------------------------------------------------------- 1 | package com.mohiva.play.silhouette 2 | 3 | import scala.collection.immutable.Map 4 | 5 | private[silhouette] object ScalaCompat { 6 | 7 | implicit class MapOps[K, V](val map: Map[K, V]) extends AnyVal { 8 | def transformValues[W](f: V => W): Map[K, W] = map.view.mapValues(f).toMap 9 | } 10 | 11 | val JavaConverters = scala.jdk.CollectionConverters 12 | } 13 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/custom/auth0.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2NtLXRlc3QuZXUuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDU2YmIwODVmZGE1OTU4NjQwMjcyZmI5YSIsImF1ZCI6Im15SDM2eDZyMTh0TEhxRGxjR21FbGJTd1paZGdjUXpoIiwiZXhwIjoxNDU1MTMzOTkxLCJpYXQiOjE0NTUwOTc5OTF9.hH5Bim8NpVwnw0hEZ3psoq4pjrwbVBgXXh7udcvL8os", 3 | "access_token": "uytvrlJcwrGtvejb", 4 | "token_type": "bearer" 5 | } 6 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/custom/facebook.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "134405962728980", 3 | "name": "Apollonia Vanova", 4 | "first_name": "Apollonia", 5 | "last_name": "Vanova", 6 | "email": "apollonia.vanova@watchmen.com", 7 | "gender": "male", 8 | "picture": { 9 | "data": { 10 | "url": "https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-ash2/t1/36245_155530314499277_2350717_n.jpg?lvh=1" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/xing.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "id": "1235468792", 5 | "first_name": "Apollonia", 6 | "last_name": "Vanova", 7 | "display_name": "Apollonia Vanova", 8 | "active_email": "apollonia.vanova@watchmen.com", 9 | "photo_urls": { 10 | "large": "http://www.xing.com/img/users/e/3/d/f94ef165a.123456,1.140x185.jpg" 11 | } 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/twitter.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 6253282, 3 | "id_str": "6253282", 4 | "name": "Apollonia Vanova", 5 | "screen_name": "apolloniavanova", 6 | "location": "Slovak", 7 | "description": "A Slovakian-born actress, known for her roles as Silhouette in the film version of Watchmen.", 8 | "url": "http:\/\/apolloniavanova.com", 9 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1209905677/appolonia_.jpg" 10 | } 11 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/foursquare.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "code": 200 4 | }, 5 | "response": { 6 | "user": { 7 | "id": "13221052", 8 | "firstName": "Apollonia", 9 | "lastName": "Vanova", 10 | "photo": { 11 | "prefix": "https://irs0.4sqi.net/img/user/", 12 | "suffix": "/blank_girl.png" 13 | }, 14 | "contact": { 15 | "email": "apollonia.vanova@watchmen.com" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth1/twitter.with.email.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 6253282, 3 | "id_str": "6253282", 4 | "name": "Apollonia Vanova", 5 | "email": "apollonia.vanova@watchmen.com", 6 | "screen_name": "apolloniavanova", 7 | "location": "Slovak", 8 | "description": "A Slovakian-born actress, known for her roles as Silhouette in the film version of Watchmen.", 9 | "url": "http:\/\/apolloniavanova.com", 10 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1209905677/appolonia_.jpg" 11 | } 12 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/foursquare.deprecated.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "code": 200, 4 | "errorType": "deprecated" 5 | }, 6 | "response": { 7 | "user": { 8 | "id": "13221052", 9 | "firstName": "Apollonia", 10 | "lastName": "Vanova", 11 | "photo": { 12 | "prefix": "https://irs0.4sqi.net/img/user/", 13 | "suffix": "/blank_girl.png" 14 | }, 15 | "contact": { 16 | "email": "apollonia.vanova@watchmen.com" 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/vk.error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "error_code": 10, 4 | "error_msg": "Internal server error: could not get application", 5 | "request_params": [ 6 | { 7 | "key": "oauth", 8 | "value": "1" 9 | }, 10 | { 11 | "key": "method", 12 | "value": "getProfiles" 13 | }, 14 | { 15 | "key": "fields", 16 | "value": "uid,first_name,last_name,photo" 17 | }, 18 | { 19 | "key": "access_token", 20 | "value":"test.token" 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /silhouette/build.sbt: -------------------------------------------------------------------------------- 1 | import Dependencies._ 2 | 3 | libraryDependencies ++= Seq( 4 | Library.Play.cache, 5 | Library.Play.ws, 6 | Library.Play.openid, 7 | Library.Play.jsonJoda, 8 | Library.jwtCore, 9 | Library.jwtApi, 10 | Library.apacheCommonLang, 11 | Library.Play.specs2 % Test, 12 | Library.Specs2.matcherExtra % Test, 13 | Library.Specs2.mock % Test, 14 | Library.scalaGuice % Test, 15 | Library.akkaTestkit % Test 16 | ) 17 | 18 | enablePlugins(PlayScala, Doc) 19 | 20 | unmanagedSourceDirectories in Compile += { 21 | baseDirectory.value / (if(Util.priorTo213(scalaVersion.value)) "app-2.13-" else "app-2.13+") 22 | } 23 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/linkedin.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "NhZXBl_O6f", 3 | "localizedFirstName": "Apollonia", 4 | "localizedLastName": "Vanova", 5 | "lastName": { 6 | "localized": { 7 | "en_US": "Vanova" 8 | }, 9 | "preferredLocale": { 10 | "country": "US", 11 | "language": "en" 12 | } 13 | }, 14 | "firstName": { 15 | "localized": { 16 | "en_US": "Apollonia" 17 | }, 18 | "preferredLocale": { 19 | "country": "US", 20 | "language": "en" 21 | } 22 | }, 23 | "profilePicture": { 24 | "displayImage": "urn:li:digitalmediaAsset:Ue2fjKLUZkB2FL6TOe2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Pull Request Checklist 2 | 3 | * [ ] Have you read [How to write the perfect pull request](https://github.com/blog/1943-how-to-write-the-perfect-pull-request)? 4 | * [ ] Have you read through the [contributor guidelines](https://github.com/mohiva/play-silhouette/blob/master/CONTRIBUTING.md)? 5 | * [ ] Have you added copyright headers to new files? 6 | * [ ] Have you suggest documentation edits? 7 | * [ ] Have you added tests for any changed functionality? 8 | 9 | ## Fixes 10 | 11 | Fixes #xxxx 12 | 13 | ## Purpose 14 | 15 | What does this PR do? 16 | 17 | ## Background Context 18 | 19 | Why did you take this approach? 20 | 21 | ## References 22 | 23 | Are there any relevant issues / PRs / mailing lists discussions? 24 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | // Comment to get more information during initialization 2 | logLevel := Level.Warn 3 | 4 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.1") 5 | 6 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1") 7 | 8 | addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7") 9 | 10 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0") 11 | 12 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.1") 13 | 14 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") 15 | 16 | addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.2") 17 | 18 | addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.8.2") 19 | 20 | addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.3") 21 | 22 | addSbtPlugin("com.dwijnand" % "sbt-travisci" % "1.2.0") 23 | -------------------------------------------------------------------------------- /silhouette/conf/reference.conf: -------------------------------------------------------------------------------- 1 | play.i18n.langs = [ "en", "en-US" ] 2 | 3 | # Secret key 4 | # ~~~~~ 5 | # The secret key is used to secure cryptographics functions. 6 | # If you deploy your application to several instances be sure to use the same key! 7 | play.http.secret.key="1s`20s2deE$r;Io]w^fpx:x^HEQ9eyeF7H:MS10iGOxdh1GH5p/hDw=Sq[ieK]Ndwfg" 8 | 9 | # The application DI modules 10 | # ~~~~~ 11 | play.modules.enabled += "com.mohiva.play.silhouette.api.actions.SecuredActionModule" 12 | play.modules.enabled += "com.mohiva.play.silhouette.api.actions.SecuredErrorHandlerModule" 13 | play.modules.enabled += "com.mohiva.play.silhouette.api.actions.UnsecuredActionModule" 14 | play.modules.enabled += "com.mohiva.play.silhouette.api.actions.UnsecuredErrorHandlerModule" 15 | play.modules.enabled += "com.mohiva.play.silhouette.api.actions.UserAwareActionModule" 16 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/custom/auth0.profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "email": "john@company.org", 3 | "email_verified": true, 4 | "clientID": "tSWS3Y1pFaFbY4v3hPwYa46TepGtg875", 5 | "updated_at": "2016-02-10T11:05:23.689Z", 6 | "picture": "https://s.gravatar.com/avatar/c1c49231ce863e5f33d7f42cd44632f4?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Flu.png", 7 | "user_id": "auth0|56961100fc02d8a0339b1a2a", 8 | "name": "john@company.org", 9 | "nickname": "john", 10 | "identities": [ 11 | { 12 | "user_id": "56961100fc02d8a0339b1a2a", 13 | "provider": "auth0", 14 | "connection": "Username-Password-Authentication", 15 | "isSocial": false 16 | } 17 | ], 18 | "created_at": "2016-01-13T08:55:28.389Z", 19 | "last_password_reset": "2016-02-08T11:14:20.663Z", 20 | "sub": "auth0|56961100fc02d8a0339b1a2a" 21 | } -------------------------------------------------------------------------------- /scripts/reformat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Reformats source code. 4 | # 5 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | set -o nounset -o errexit 20 | 21 | scripts/sbt clean scalariformFormat test:scalariformFormat build:scalariformFormat 22 | -------------------------------------------------------------------------------- /scripts/sbt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Runs sbt with default options. 4 | # 5 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | set -o nounset -o errexit 20 | 21 | scripts/sbt-runner -jvm-opts project/build-jvm-opts ++$TRAVIS_SCALA_VERSION "$@" 22 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.error.api.missing.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "code": 403, 4 | "message": "People API has not been used in project 1234567890 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=1234567890 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.", 5 | "status": "PERMISSION_DENIED", 6 | "details": [ 7 | { 8 | "@type": "type.googleapis.com/google.rpc.Help", 9 | "links": [ 10 | { 11 | "description": "Google developers console API activation", 12 | "url": "https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=1234567890" 13 | } 14 | ] 15 | } 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/AuthInfo.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * A marker trait for authentication information. 20 | */ 21 | trait AuthInfo 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * Provides utilities used by the API. 20 | */ 21 | package object util {} 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette 17 | 18 | /** 19 | * The reference implementation of Silhouette. 20 | */ 21 | package object impl 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * Provides exceptions used by the API. 20 | */ 21 | package object exceptions 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/util/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl 17 | 18 | /** 19 | * Provides implementations of utility traits. 20 | */ 21 | package object util {} 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/services/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl 17 | 18 | /** 19 | * Provides implementations of the services. 20 | */ 21 | package object services {} 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette 17 | 18 | /** 19 | * The collection of traits and utility classes that form the stable API of Silhouette. 20 | */ 21 | package object api 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/authenticators/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl 17 | 18 | /** 19 | * Reference implementations of the authenticators. 20 | */ 21 | package object authenticators 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl 17 | 18 | /** 19 | * Provides exceptions thrown in the reference implementation. 20 | */ 21 | package object exceptions 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/repositories/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * Provides repositories used by the API to persist entities. 20 | */ 21 | package object repositories {} 22 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/services/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * Provides services used by the API to call external or internal services. 20 | */ 21 | package object services {} 22 | -------------------------------------------------------------------------------- /scripts/coveralls: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Publishes the coverage report to http://coveralls.io. 4 | # 5 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | set -o nounset -o errexit 20 | 21 | echo "" 22 | echo "Publish coverage report" 23 | scripts/sbt coveralls 24 | 25 | echo "" 26 | echo "Report published" 27 | echo "" 28 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/daos/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence 17 | 18 | /** 19 | * Provides DAO implementations to persist and retrieve objects. 20 | */ 21 | package object daos 22 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/repositories/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence 17 | 18 | /** 19 | * Provides implementations of the repositories. 20 | */ 21 | package object repositories {} 22 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.without.email.json: -------------------------------------------------------------------------------- 1 | { 2 | "resourceName": "people/109476598527568979481", 3 | "etag": "%EggBAj0DCT43LohDUMMYVALUEgbwgJCgsMIgxkaGtKb3cwenMxMD1=", 4 | "names": [ 5 | { 6 | "metadata": { 7 | "primary": true, 8 | "source": { 9 | "type": "PROFILE", 10 | "id": "109476598527568979481" 11 | } 12 | }, 13 | "displayName": "Apollonia Vanova", 14 | "familyName": "Vanova", 15 | "givenName": "Apollonia", 16 | "displayNameLastFirst": "Vanova, Apollonia" 17 | } 18 | ], 19 | "photos": [ 20 | { 21 | "metadata": { 22 | "primary": true, 23 | "source": { 24 | "type": "PROFILE", 25 | "id": "109476598527568979481" 26 | } 27 | }, 28 | "url": "https://lh6.googleusercontent.com/-m34A6I77dJU/ASASAASADAAI/AVABAAAAAJk/5cg1hcjo_4s/photo.jpg?sz=50" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | scala: 3 | - 2.12.10 4 | - 2.13.1 5 | jdk: 6 | - openjdk8 7 | - openjdk11 8 | - openjdk12 9 | env: 10 | global: 11 | - ENCRYPTION_ID: "9eb27d59440e" 12 | before_script: 13 | - echo "TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG, TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST, TRAVIS_BRANCH=$TRAVIS_BRANCH" 14 | # caching scala stuff based on 15 | # https://www.scala-sbt.org/1.x/docs/Travis-CI-with-sbt.html 16 | before_cache: 17 | # Tricks to avoid unnecessary cache updates 18 | - rm -fv $HOME/.ivy2/.sbt.ivy.lock 19 | - find $HOME/.ivy2/cache -name "ivydata-*.properties" -print -delete 20 | - find $HOME/.sbt -name "*.lock" -print -delete 21 | cache: 22 | directories: 23 | - $HOME/.cache/coursier 24 | - $HOME/.ivy2/cache 25 | - $HOME/.sbt 26 | script: 27 | - scripts/ci-build 28 | after_success: 29 | - scripts/api-doc 30 | - scripts/coveralls 31 | notifications: 32 | email: false 33 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/Logger.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | /** 19 | * Implement this to get a named logger in scope. 20 | */ 21 | trait Logger { 22 | 23 | /** 24 | * A named logger instance. 25 | */ 26 | val logger = play.api.Logger(this.getClass) 27 | } 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/SilhouetteException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * A marker exception for the Silhouette project. 20 | */ 21 | class SilhouetteException(msg: String, cause: Throwable = null) 22 | extends Exception(msg, cause) 23 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/providers/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl 17 | 18 | /** 19 | * Contains [[com.mohiva.play.silhouette.api.Provider]] implementations that provide authentication 20 | * for different schemes and services. 21 | */ 22 | package object providers {} 23 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception for all authenticator related errors. 20 | */ 21 | class AuthenticatorException(msg: String, cause: Throwable = null) 22 | extends SilhouetteException(msg, cause) 23 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/Credentials.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | /** 19 | * Credentials to authenticate with. 20 | * 21 | * @param identifier The unique identifier to authenticate with. 22 | * @param password The password to authenticate with. 23 | */ 24 | case class Credentials(identifier: String, password: String) 25 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/CryptoException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * Indicates that a crypto operation error occurred. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class CryptoException(msg: String, cause: Throwable = null) 25 | extends SilhouetteException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/ProviderException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * Indicates an error occurred with an authentication provider. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class ProviderException(msg: String, cause: Throwable = null) 25 | extends SilhouetteException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/ConfigurationException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * Indicates a misconfiguration of a Silhouette component. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class ConfigurationException(msg: String, cause: Throwable = null) 25 | extends SilhouetteException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/Identity.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.api 21 | 22 | /** 23 | * This trait represents an authenticated user. 24 | */ 25 | trait Identity 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/NotAuthenticatedException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * Indicates that a user is not authenticated to access a secured endpoint. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class NotAuthenticatedException(msg: String, cause: Throwable = null) 25 | extends SilhouetteException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorUpdateException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator update. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorUpdateException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/NotAuthorizedException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * Indicates that the authenticated user is not authorized to access a secured endpoint. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class NotAuthorizedException(msg: String, cause: Throwable = null) 25 | extends SilhouetteException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorRenewalException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator renewal. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorRenewalException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/ExecutionContextProvider.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import scala.concurrent.ExecutionContext 19 | 20 | /** 21 | * A trait that can be mixed in to provide an execution context. 22 | */ 23 | trait ExecutionContextProvider { 24 | 25 | /** 26 | * The execution context to handle the asynchronous operations. 27 | */ 28 | implicit val executionContext: ExecutionContext 29 | } 30 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorCreationException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator creation. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorCreationException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorRetrievalException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator retrieval. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorRetrievalException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorDiscardingException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator discarding. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorDiscardingException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/exceptions/AuthenticatorInitializationException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.exceptions 17 | 18 | /** 19 | * An exception thrown when there is an error during authenticator initialization. 20 | * 21 | * @param msg The exception message. 22 | * @param cause The exception cause. 23 | */ 24 | class AuthenticatorInitializationException(msg: String, cause: Throwable = null) 25 | extends AuthenticatorException(msg, cause) 26 | -------------------------------------------------------------------------------- /scripts/ci-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Builds the project in the continuous integration environment. 4 | # 5 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | set -o nounset -o errexit 20 | 21 | echo "" 22 | echo "Validating code formatting" 23 | scripts/validate-format 24 | 25 | echo "" 26 | echo "Testing and generating documentation" 27 | scripts/sbt clean coverage test doc coverageReport 28 | 29 | echo "" 30 | echo "Aggregate coverage from sub-projects" 31 | scripts/sbt coverageAggregate 32 | 33 | echo "" 34 | echo "Build finished" 35 | echo "" 36 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/OAuth2StateException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Indicates that an error occurred during OAuth2 state retrieval. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class OAuth2StateException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/AccessDeniedException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Signals that a social provider denies access during authentication process. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class AccessDeniedException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/IdentityNotFoundException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Signals that an identity could not found in a credential based provider. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class IdentityNotFoundException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/OAuth1TokenSecretException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Indicates that an error occurred during OAuth1 token secret retrieval. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class OAuth1TokenSecretException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/InvalidPasswordException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Indicates that an invalid password was entered in a credential based provider. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class InvalidPasswordException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/UnexpectedResponseException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Signals that an unexpected response was received from a social provider. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class UnexpectedResponseException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/exceptions/ProfileRetrievalException.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.exceptions 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.ProviderException 19 | 20 | /** 21 | * Indicates that an error occurred during profile retrieval in a social provider. 22 | * 23 | * @param msg The exception message. 24 | * @param cause The exception cause. 25 | */ 26 | class ProfileRetrievalException(msg: String, cause: Throwable = null) 27 | extends ProviderException(msg, cause) 28 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/gitlab.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "username": "john_smith", 4 | "email": "john@example.com", 5 | "name": "John Smith", 6 | "state": "active", 7 | "avatar_url": "http://gitlab.com/uploads/user/avatar/1/index.jpg", 8 | "web_url": "http://gitlab.com/u/john_smith", 9 | "created_at": "2012-05-23T08:00:58Z", 10 | "is_admin": false, 11 | "bio": null, 12 | "location": null, 13 | "skype": "", 14 | "linkedin": "", 15 | "twitter": "", 16 | "website_url": "", 17 | "last_sign_in_at": "2012-06-01T11:41:01Z", 18 | "confirmed_at": "2012-05-23T09:05:22Z", 19 | "theme_id": 1, 20 | "color_scheme_id": 2, 21 | "projects_limit": 100, 22 | "current_sign_in_at": "2012-06-02T06:36:55Z", 23 | "identities": [ 24 | { 25 | "provider": "github", 26 | "extern_uid": "2435223452345" 27 | }, 28 | { 29 | "provider": "bitbucket", 30 | "extern_uid": "john_smith" 31 | }, 32 | { 33 | "provider": "google_oauth2", 34 | "extern_uid": "8776128412476123468721346" 35 | } 36 | ], 37 | "can_create_group": true, 38 | "can_create_project": true, 39 | "two_factor_enabled": true, 40 | "external": false, 41 | "private_token": "dd34asd13as" 42 | } 43 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/util/ClockSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import org.joda.time.DateTime 19 | import play.api.test._ 20 | 21 | /** 22 | * Test case for the [[com.mohiva.play.silhouette.api.util.Clock]] class. 23 | */ 24 | class ClockSpec extends PlaySpecification { 25 | 26 | "The `apply` method" should { 27 | "return a new Clock instance" in { 28 | Clock() should beAnInstanceOf[Clock] 29 | } 30 | } 31 | 32 | "The `now` method" should { 33 | "return a new DateTime instance" in { 34 | Clock().now should beAnInstanceOf[DateTime] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/Clock.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import org.joda.time.DateTime 19 | 20 | /** 21 | * A trait which provides a mockable implementation for a DateTime instance. 22 | */ 23 | trait Clock { 24 | 25 | /** 26 | * Gets the current DateTime. 27 | * 28 | * @return the current DateTime. 29 | */ 30 | def now: DateTime 31 | } 32 | 33 | /** 34 | * Creates a clock implementation. 35 | */ 36 | object Clock { 37 | 38 | /** 39 | * Gets a Clock implementation. 40 | * 41 | * @return A Clock implementation. 42 | */ 43 | def apply() = new Clock { 44 | def now = DateTime.now 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/crypto/Signer.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import scala.util.Try 19 | 20 | /** 21 | * Specifies a strategy how data can be signed. 22 | */ 23 | trait Signer { 24 | 25 | /** 26 | * Signs the given data using the given secret key. 27 | * 28 | * @param data The data to sign. 29 | * @return A message authentication code. 30 | */ 31 | def sign(data: String): String 32 | 33 | /** 34 | * Extracts a message that was signed by [[Signer.sign]]. 35 | * 36 | * @param message The signed message to extract. 37 | * @return The verified raw data, or an error if the message isn't valid. 38 | */ 39 | def extract(message: String): Try[String] 40 | } 41 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/crypto/HashSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import play.api.test._ 19 | 20 | /** 21 | * Test case for the [[com.mohiva.play.silhouette.api.crypto.Hash]] object. 22 | */ 23 | class HashSpec extends PlaySpecification { 24 | 25 | "The `sha1` method" should { 26 | "create a SHA1 hash of a string" in { 27 | Hash.sha1("SÄÜ%&/($§QW@\\'Ä_:;>|§`´*~") must be equalTo "a87babacb5ef14f1f811527c2028706a55c56be5" 28 | } 29 | } 30 | 31 | "The `sha2` method" should { 32 | "create a SHA2 hash of a string" in { 33 | Hash.sha2("SÄÜ%&/($§QW@\\'Ä_:;>|§`´*~") must be equalTo "162b62e492f8f4d979d5f96c1fb96c7bf5c0621f48f0613bf16fa527e41c54e5" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/FingerprintGenerator.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.api.util 21 | 22 | import play.api.mvc.RequestHeader 23 | 24 | /** 25 | * A generator which creates a fingerprint to identify a user. 26 | */ 27 | trait FingerprintGenerator { 28 | 29 | /** 30 | * Generates a fingerprint from request. 31 | * 32 | * @param request The request header. 33 | * @return The generated fingerprint. 34 | */ 35 | def generate(implicit request: RequestHeader): String 36 | } 37 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/crypto/Base64Spec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import play.api.libs.json.Json 19 | import play.api.test._ 20 | 21 | /** 22 | * Test case for the [[Base64]] object. 23 | */ 24 | class Base64Spec extends PlaySpecification { 25 | 26 | "The `decode` method" should { 27 | "decode a Base64 string" in { 28 | Base64.decode("SGVsbG8gV29ybGQh") must be equalTo "Hello World!" 29 | } 30 | } 31 | 32 | "The `encode` method" should { 33 | "encode a string as Base64" in { 34 | Base64.encode("Hello World!") must be equalTo "SGVsbG8gV29ybGQh" 35 | } 36 | 37 | "encode Json as Base64" in { 38 | Base64.encode(Json.obj("word" -> "Hello World!")) must be equalTo "eyJ3b3JkIjoiSGVsbG8gV29ybGQhIn0=" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "resourceName": "people/109476598527568979481", 3 | "etag": "%EggBAj0DCT43LohDUMMYVALUEgbwgJCgsMIgxkaGtKb3cwenMxMD1=", 4 | "emailAddresses": [ 5 | { 6 | "metadata": { 7 | "primary": true, 8 | "verified": true, 9 | "source": { 10 | "type": "ACCOUNT", 11 | "id": "109476598527568979481" 12 | } 13 | }, 14 | "value": "apollonia.vanova@watchmen.com" 15 | }, 16 | { 17 | "metadata": { 18 | "verified": true, 19 | "source": { 20 | "type": "ACCOUNT", 21 | "id": "109476598527568979481" 22 | } 23 | }, 24 | "value": "home@watchmen.com" 25 | } 26 | ], 27 | "names": [ 28 | { 29 | "metadata": { 30 | "primary": true, 31 | "source": { 32 | "type": "PROFILE", 33 | "id": "109476598527568979481" 34 | } 35 | }, 36 | "displayName": "Apollonia Vanova", 37 | "familyName": "Vanova", 38 | "givenName": "Apollonia", 39 | "displayNameLastFirst": "Vanova, Apollonia" 40 | } 41 | ], 42 | "photos": [ 43 | { 44 | "metadata": { 45 | "primary": true, 46 | "source": { 47 | "type": "PROFILE", 48 | "id": "109476598527568979481" 49 | } 50 | }, 51 | "url": "https://lh6.googleusercontent.com/-m34A6I77dJU/ASASAASADAAI/AVABAAAAAJk/5cg1hcjo_4s/photo.jpg?sz=50" 52 | } 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/JsonFormats.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import play.api.libs.json._ 19 | import play.api.libs.json.Reads._ 20 | import play.api.libs.json.Writes._ 21 | 22 | import scala.concurrent.duration._ 23 | 24 | /** 25 | * Some implicit Json formats. 26 | */ 27 | object JsonFormats { 28 | 29 | /** 30 | * Converts [[scala.concurrent.duration.FiniteDuration]] object to JSON and vice versa. 31 | * 32 | * We use seconds here because it the smallest unit used by Silhouette. 33 | */ 34 | implicit object FiniteDurationFormat extends Format[FiniteDuration] { 35 | def reads(json: JsValue): JsResult[FiniteDuration] = LongReads.reads(json).map(_.seconds) 36 | def writes(o: FiniteDuration): JsValue = LongWrites.writes(o.toSeconds) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /silhouette-persistence/src/test/scala/com/mohiva/play/silhouette/test/WaitPatience.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.test 17 | 18 | import org.specs2.concurrent.ExecutionEnv 19 | import org.specs2.matcher.FutureMatchers.FutureMatchable 20 | import org.specs2.matcher.Matcher 21 | 22 | import scala.concurrent.Future 23 | import scala.concurrent.duration._ 24 | 25 | /** 26 | * Helper to wait with patience to a result. 27 | * 28 | * This is needed to prevent the tests for timeouts. 29 | */ 30 | trait WaitPatience { 31 | 32 | def retries = 10 33 | 34 | def timeout = 1.second 35 | 36 | implicit class WaitWithPatienceFutureMatchable[T](m: Matcher[T])(implicit ee: ExecutionEnv) extends FutureMatchable[T](m)(ee) { 37 | def awaitWithPatience: Matcher[Future[T]] = { 38 | await(retries, timeout) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/services/AvatarService.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.api.services 21 | 22 | import scala.concurrent.Future 23 | 24 | /** 25 | * Service to retrieve avatar URLs from an avatar service such as Gravatar. 26 | */ 27 | trait AvatarService { 28 | 29 | /** 30 | * Retrieves the URL for an identifier. 31 | * 32 | * @param id The identifier for the avatar. 33 | * @return Maybe an avatar URL or None if no URL could be found for the given identifier. 34 | */ 35 | def retrieveURL(id: String): Future[Option[String]] 36 | } 37 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/IDGenerator.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.api.util 21 | 22 | import scala.concurrent.Future 23 | 24 | /** 25 | * A generator which creates an ID. 26 | */ 27 | trait IDGenerator { 28 | 29 | /** 30 | * Generates an ID. 31 | * 32 | * Generating secure IDs can block the application, while the system waits for resources. Therefore we 33 | * return a future so that the application doesn't get blocked while waiting for the generated ID. 34 | * 35 | * @return The generated ID. 36 | */ 37 | def generate: Future[String] 38 | } 39 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.img.non-default.json: -------------------------------------------------------------------------------- 1 | { 2 | "resourceName": "people/109476598527568979481", 3 | "etag": "%EggBAj0DCT43LohDUMMYVALUEgbwgJCgsMIgxkaGtKb3cwenMxMD1=", 4 | "emailAddresses": [ 5 | { 6 | "metadata": { 7 | "primary": true, 8 | "verified": true, 9 | "source": { 10 | "type": "ACCOUNT", 11 | "id": "109476598527568979481" 12 | } 13 | }, 14 | "value": "apollonia.vanova@watchmen.com" 15 | }, 16 | { 17 | "metadata": { 18 | "primary": true, 19 | "verified": true, 20 | "source": { 21 | "type": "HOME", 22 | "id": "109476598527568979481" 23 | } 24 | }, 25 | "value": "home@watchmen.com" 26 | } 27 | ], 28 | "names": [ 29 | { 30 | "metadata": { 31 | "primary": true, 32 | "source": { 33 | "type": "PROFILE", 34 | "id": "109476598527568979481" 35 | } 36 | }, 37 | "displayName": "Apollonia Vanova", 38 | "familyName": "Vanova", 39 | "givenName": "Apollonia", 40 | "displayNameLastFirst": "Vanova, Apollonia" 41 | } 42 | ], 43 | "photos": [ 44 | { 45 | "metadata": { 46 | "primary": true, 47 | "source": { 48 | "type": "PROFILE", 49 | "id": "109476598527568979481" 50 | } 51 | }, 52 | "url": "https://lh6.googleusercontent.com/-m34A6I77dJU/ASASAASADAAI/AVABAAAAAJk/5cg1hcjo_4s/photo.jpg?sz=50" 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/util/PlayHTTPLayerSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import play.api.libs.ws.{ WSClient, WSRequest } 19 | import play.api.test._ 20 | 21 | import scala.concurrent.ExecutionContext.Implicits.global 22 | 23 | /** 24 | * Test case for the [[com.mohiva.play.silhouette.api.util.PlayHTTPLayer]] class. 25 | */ 26 | class PlayHTTPLayerSpec extends PlaySpecification { 27 | 28 | "The `url` method" should { 29 | "return a new WS.WSRequest instance" in new WithApplication { 30 | val url = "http://silhouette.mohiva.com" 31 | val client = app.injector.instanceOf[WSClient] 32 | val httpLayer = new PlayHTTPLayer(client) 33 | val requestHolder = httpLayer.url(url) 34 | 35 | requestHolder should beAnInstanceOf[WSRequest] 36 | requestHolder.url must be equalTo url 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /silhouette/test/resources/providers/oauth2/google.img.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "resourceName": "people/109476598527568979481", 3 | "etag": "%EggBAj0DCT43LohDUMMYVALUEgbwgJCgsMIgxkaGtKb3cwenMxMD1=", 4 | "emailAddresses": [ 5 | { 6 | "metadata": { 7 | "primary": true, 8 | "verified": true, 9 | "source": { 10 | "type": "ACCOUNT", 11 | "id": "109476598527568979481" 12 | } 13 | }, 14 | "value": "apollonia.vanova@watchmen.com" 15 | }, 16 | { 17 | "metadata": { 18 | "primary": true, 19 | "verified": true, 20 | "source": { 21 | "type": "HOME", 22 | "id": "109476598527568979481" 23 | } 24 | }, 25 | "value": "home@watchmen.com" 26 | } 27 | ], 28 | "names": [ 29 | { 30 | "metadata": { 31 | "primary": true, 32 | "source": { 33 | "type": "PROFILE", 34 | "id": "109476598527568979481" 35 | } 36 | }, 37 | "displayName": "Apollonia Vanova", 38 | "familyName": "Vanova", 39 | "givenName": "Apollonia", 40 | "displayNameLastFirst": "Vanova, Apollonia" 41 | } 42 | ], 43 | "photos": [ 44 | { 45 | "metadata": { 46 | "primary": true, 47 | "source": { 48 | "type": "PROFILE", 49 | "id": "109476598527568979481" 50 | } 51 | }, 52 | "url": "https://lh6.googleusercontent.com/-m34A6I77dJU/ASASAASADAAI/AVABAAAAAJk/5cg1hcjo_4s/photo.jpg?sz=50", 53 | "default": true 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/crypto/Crypter.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | /** 19 | * Crypter interface. 20 | * 21 | * This trait provides a generic encryption/decryption interface for the core, for which a concrete 22 | * implementation can be provided in userland. 23 | * 24 | * It's not guaranteed that the concrete implementations are compatible to each other. This means that 25 | * they cannot act as drop-in replacements. 26 | */ 27 | trait Crypter { 28 | 29 | /** 30 | * Encrypts a string. 31 | * 32 | * @param value The plain text to encrypt. 33 | * @return The encrypted string. 34 | */ 35 | def encrypt(value: String): String 36 | 37 | /** 38 | * Decrypts a string. 39 | * 40 | * @param value The value to decrypt. 41 | * @return The plain text string. 42 | */ 43 | def decrypt(value: String): String 44 | } 45 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/LoginInfo.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | import play.api.libs.json.Json 19 | 20 | /** 21 | * Represents a linked login for an identity (i.e. a local username/password or a Facebook/Google account). 22 | * 23 | * The login info contains the data about the provider that authenticated that identity. 24 | * 25 | * @param providerID The ID of the provider. 26 | * @param providerKey A unique key which identifies a user on this provider (userID, email, ...). 27 | */ 28 | case class LoginInfo(providerID: String, providerKey: String) 29 | 30 | /** 31 | * The companion object of the login info. 32 | */ 33 | object LoginInfo extends ((String, String) => LoginInfo) { 34 | 35 | /** 36 | * Converts the [[com.mohiva.play.silhouette.api.LoginInfo]] to Json and vice versa. 37 | */ 38 | implicit val jsonFormat = Json.format[LoginInfo] 39 | } 40 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/openid/service/PlayOpenIDServiceSpec.scala: -------------------------------------------------------------------------------- 1 | package com.mohiva.play.silhouette.impl.providers.openid.service 2 | 3 | import com.mohiva.play.silhouette.impl.providers.OpenIDSettings 4 | import com.mohiva.play.silhouette.impl.providers.openid.services.PlayOpenIDService 5 | import org.specs2.mock.Mockito 6 | import org.specs2.specification.Scope 7 | import play.api.libs.openid.OpenIdClient 8 | import play.api.test.{ PlaySpecification, WithApplication } 9 | 10 | class PlayOpenIDServiceSpec extends PlaySpecification with Mockito { 11 | 12 | "The `withSettings` method" should { 13 | "create a new instance with customized settings" in new WithApplication with Context { 14 | val s = service.withSettings { s => 15 | s.copy("new-provider-url") 16 | } 17 | 18 | s.settings.providerURL must be equalTo "new-provider-url" 19 | } 20 | } 21 | 22 | /** 23 | * The context. 24 | */ 25 | trait Context extends Scope { 26 | /** 27 | * The OpenID settings. 28 | */ 29 | lazy val openIDSettings = OpenIDSettings( 30 | providerURL = "https://me.yahoo.com/", 31 | callbackURL = "http://localhost:9000/authenticate/yahoo", 32 | axRequired = Map( 33 | "fullname" -> "http://axschema.org/namePerson", 34 | "email" -> "http://axschema.org/contact/email", 35 | "image" -> "http://axschema.org/media/image/default" 36 | ), 37 | realm = Some("http://localhost:9000") 38 | ) 39 | 40 | val service = new PlayOpenIDService(mock[OpenIdClient], openIDSettings) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/daos/DelegableAuthInfoDAO.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence.daos 17 | 18 | import com.mohiva.play.silhouette.api.AuthInfo 19 | 20 | import scala.reflect.ClassTag 21 | 22 | /** 23 | * An implementation of the auth info DAO. 24 | * 25 | * This abstract implementation of the [[com.mohiva.play.silhouette.persistence.daos.AuthInfoDAO]] trait 26 | * allows us to get the class tag of the auth info it is responsible for. Based on the class tag 27 | * the [[com.mohiva.play.silhouette.persistence.repositories.DelegableAuthInfoRepository]] class 28 | * can delegate operations to the DAO which is responsible for the currently handled auth info. 29 | * 30 | * @tparam T The type of the auth info to store. 31 | */ 32 | trait DelegableAuthInfoDAO[T <: AuthInfo] extends AuthInfoDAO[T] { 33 | 34 | /** 35 | * The class tag for the type parameter. 36 | */ 37 | val classTag: ClassTag[T] 38 | } 39 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/services/IdentityService.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.api.services 21 | 22 | import com.mohiva.play.silhouette.api.{ Identity, LoginInfo } 23 | 24 | import scala.concurrent.Future 25 | 26 | /** 27 | * A trait that provides the means to retrieve identities for the Silhouette module. 28 | */ 29 | trait IdentityService[T <: Identity] { 30 | 31 | /** 32 | * Retrieves an identity that matches the specified login info. 33 | * 34 | * @param loginInfo The login info to retrieve an identity. 35 | * @return The retrieved identity or None if no identity could be retrieved for the given login info. 36 | */ 37 | def retrieve(loginInfo: LoginInfo): Future[Option[T]] 38 | } 39 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/util/SecureRandomIDGeneratorSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.util 17 | 18 | import play.api.test.PlaySpecification 19 | 20 | import scala.concurrent.ExecutionContext.Implicits.global 21 | 22 | /** 23 | * Test case for the [[com.mohiva.play.silhouette.impl.util.SecureRandomIDGenerator]] class. 24 | */ 25 | class SecureRandomIDGeneratorSpec extends PlaySpecification { 26 | 27 | "The generator" should { 28 | "return a 128 byte length secure random number" in { 29 | val generator = new SecureRandomIDGenerator() 30 | val id = await(generator.generate) 31 | 32 | id must have size (128 * 2) 33 | id must beMatching("[a-f0-9]+") 34 | } 35 | 36 | "return a 265 byte length secure random number" in { 37 | val generator = new SecureRandomIDGenerator(256) 38 | val id = await(generator.generate) 39 | 40 | id must have size (256 * 2) 41 | id must beMatching("[a-f0-9]+") 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/validate-format: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Validates the code formatting. 4 | # 5 | # If there are style violations, outputs a message and exits with a non-zero status code. 6 | # 7 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | set -o nounset -o errexit 22 | 23 | git diff --quiet || ( 24 | echo "ERROR: The code formatting validation must be run on a repository with no pending changes." 25 | false 26 | ) 27 | 28 | scripts/reformat 29 | 30 | git config color.diff.whitespace "red reverse ul" 31 | git --no-pager diff -R --color --exit-code || ( 32 | echo "" 33 | echo "ERROR: The code is not formatted according to the project's standards." 34 | echo "The differences are shown above. Your code is shown in green and the expected format is shown in red." 35 | echo "To perform this same validation on your environment, run 'scripts/validate-format'." 36 | echo "To fix, format your sources running 'scripts/reformat' before submitting a pull request." 37 | echo "After correcting, please squash your commits (eg, use 'git commit --amend') before updating your pull request." 38 | false 39 | ) 40 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/User.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.impl 21 | 22 | import com.mohiva.play.silhouette.api.{ Identity, LoginInfo } 23 | 24 | /** 25 | * The default implementation of Identity. 26 | * 27 | * @param loginInfo The linked login info. 28 | * @param firstName Maybe the first name of the authenticated user. 29 | * @param lastName Maybe the last name of the authenticated user. 30 | * @param fullName Maybe the full name of the authenticated user. 31 | * @param email Maybe the email of the authenticated provider. 32 | * @param avatarURL Maybe the avatar URL of the authenticated provider. 33 | */ 34 | case class User( 35 | loginInfo: LoginInfo, 36 | firstName: Option[String], 37 | lastName: Option[String], 38 | fullName: Option[String], 39 | email: Option[String], 40 | avatarURL: Option[String]) extends Identity 41 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/crypto/Base64.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import play.api.libs.json.JsValue 19 | 20 | /** 21 | * Base64 helper. 22 | */ 23 | object Base64 { 24 | 25 | /** 26 | * Decodes a Base64 string. 27 | * 28 | * @param str The string to decode. 29 | * @return The decoded string. 30 | */ 31 | def decode(str: String): String = new String(java.util.Base64.getDecoder.decode(str), "UTF-8") 32 | 33 | /** 34 | * Encodes a byte array as Base64. 35 | * 36 | * @param bytes The byte array to encode. 37 | * @return The encodes string. 38 | */ 39 | def encode(bytes: Array[Byte]): String = java.util.Base64.getEncoder.encodeToString(bytes) 40 | 41 | /** 42 | * Encodes a string as Base64. 43 | * 44 | * @param str The string to encode. 45 | * @return The encodes string. 46 | */ 47 | def encode(str: String): String = encode(str.getBytes("UTF-8")) 48 | 49 | /** 50 | * Encodes a Json value as Base64. 51 | * 52 | * @param json The json value to encode. 53 | * @return The encoded value. 54 | */ 55 | def encode(json: JsValue): String = encode(json.toString()) 56 | } 57 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/CacheLayer.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import scala.concurrent.Future 19 | import scala.concurrent.duration.Duration 20 | import scala.reflect.ClassTag 21 | 22 | /** 23 | * A trait which provides a cache API. 24 | */ 25 | trait CacheLayer { 26 | 27 | /** 28 | * Finds a value in the cache. 29 | * 30 | * @param key The key of the item to found. 31 | * @tparam T The type of the object to return. 32 | * @return The found value or None if no value could be found. 33 | */ 34 | def find[T: ClassTag](key: String): Future[Option[T]] 35 | 36 | /** 37 | * Save a value in cache. 38 | * 39 | * @param key The item key under which the value should be saved. 40 | * @param value The value to save. 41 | * @param expiration Expiration time in seconds (0 second means eternity). 42 | * @return The value saved in cache. 43 | */ 44 | def save[T](key: String, value: T, expiration: Duration = Duration.Inf): Future[T] 45 | 46 | /** 47 | * Remove a value from the cache. 48 | * 49 | * @param key Item key. 50 | * @return An empty future to wait for removal. 51 | */ 52 | def remove(key: String): Future[Unit] 53 | } 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Are you looking for help? 2 | 3 | This is an issue tracker, used to manage and track the development of Silhouette. It is not a support system and so it is not a place to ask questions or get help. If you're not sure if you have found a bug, the best place to start is with either the [forum] or [Gitter channel]. If you have a feature request, the [forum] is better than the issue tracker to discuss it. 4 | 5 | ### Silhouette Version (4.0.x / etc) 6 | 7 | 8 | ### Operating System (Ubuntu 15.10 / MacOS 10.10 / Windows 10) 9 | 10 | Use `uname -a` if on Linux. 11 | 12 | ### JDK (Oracle 1.8.0_72, OpenJDK 1.8.x, Azul Zing) 13 | 14 | Paste the output from `java -version` at the command line. 15 | 16 | ### Library Dependencies 17 | 18 | If this is an issue that involves integration with another system, include the exact version and OS of the other system, including any intermediate drivers or APIs i.e. if you connect to a PostgreSQL database, include both the version / OS of PostgreSQL and the JDBC driver version used to connect to the database. 19 | 20 | ### Expected Behavior 21 | 22 | Please describe the expected behavior of the issue, starting from the first action. 23 | 24 | 1. 25 | 2. 26 | 3. 27 | 28 | ### Actual Behavior 29 | 30 | Please provide a description of what actually happens, working from the same starting point. 31 | 32 | Be descriptive: "it doesn't work" does not describe what the behavior actually is -- instead, provide a meaningful description of the issue. Copy and paste logs, and include any URLs. Turn on internal Silhouette logging with `` if there is no log output. 33 | 34 | 1. 35 | 2. 36 | 3. 37 | 38 | ### Reproducible Test Case 39 | 40 | Please provide a PR with a failing test. 41 | 42 | If the issue is more complex or requires configuration, please provide a link to a project on GitHub that reproduces the issue. 43 | 44 | [forum]: http://discourse.silhouette.rocks/ 45 | [Gitter channel]: https://gitter.im/mohiva/play-silhouette 46 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/crypto/AuthenticatorEncoder.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import javax.inject.Inject 19 | 20 | /** 21 | * Specifies encoding/decoding of authenticator data. 22 | */ 23 | trait AuthenticatorEncoder { 24 | 25 | /** 26 | * Encodes a string. 27 | * 28 | * @param data The data to encode. 29 | * @return The encoded data. 30 | */ 31 | def encode(data: String): String 32 | 33 | /** 34 | * Decodes a string. 35 | * 36 | * @param data The data to decode. 37 | * @return The decoded data. 38 | */ 39 | def decode(data: String): String 40 | } 41 | 42 | /** 43 | * Authenticator encoder implementation based on Base64. 44 | */ 45 | class Base64AuthenticatorEncoder extends AuthenticatorEncoder { 46 | override def encode(data: String): String = Base64.encode(data) 47 | override def decode(data: String): String = Base64.decode(data) 48 | } 49 | 50 | /** 51 | * Authenticator encoder implementation based on the [[Crypter]]. 52 | * 53 | * @param crypter The crypter instance to use for the encoder. 54 | */ 55 | class CrypterAuthenticatorEncoder @Inject() (crypter: Crypter) extends AuthenticatorEncoder { 56 | override def encode(data: String): String = crypter.encrypt(data) 57 | override def decode(data: String): String = crypter.decrypt(data) 58 | } 59 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/util/JsonFormatsSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import com.mohiva.play.silhouette.api.util.JsonFormats._ 19 | import org.specs2.matcher.JsonMatchers 20 | import play.api.libs.json.Json 21 | import play.api.test._ 22 | 23 | import scala.concurrent.duration._ 24 | 25 | /** 26 | * Test case for the [[com.mohiva.play.silhouette.api.util.JsonFormats]] class. 27 | */ 28 | class JsonFormatsSpec extends PlaySpecification with JsonMatchers { 29 | 30 | "A implicit `FiniteDurationFormat` object" should { 31 | "convert a FiniteDuration in seconds to Json" in { 32 | val json = Json.obj("value" -> 10.seconds) 33 | 34 | json.toString() must /("value" -> 10) 35 | } 36 | 37 | "convert a FiniteDuration in minutes to Json" in { 38 | val json = Json.obj("value" -> 10.minutes) 39 | 40 | json.toString() must /("value" -> (10 * 60)) 41 | } 42 | 43 | "convert Json into a FiniteDuration in seconds" in { 44 | val json = Json.obj("value" -> 10.seconds) 45 | 46 | (json \ "value").as[FiniteDuration] must be equalTo 10.seconds 47 | } 48 | 49 | "convert Json into a FiniteDuration in minutes" in { 50 | val json = Json.obj("value" -> 10.minutes) 51 | 52 | (json \ "value").as[FiniteDuration] must be equalTo 10.minutes 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/crypto/Hash.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.crypto 17 | 18 | import java.security.MessageDigest 19 | 20 | /** 21 | * Hash helper. 22 | */ 23 | object Hash { 24 | 25 | /** 26 | * Creates a SHA1 hash from the given string. 27 | * 28 | * @param str The string to create a hash from. 29 | * @return The SHA1 hash of the string. 30 | */ 31 | def sha1(str: String): String = sha1(str.getBytes("UTF-8")) 32 | 33 | /** 34 | * Creates a SHA1 hash from the given byte array. 35 | * 36 | * @param bytes The bytes to create a hash from. 37 | * @return The SHA1 hash of the bytes. 38 | */ 39 | def sha1(bytes: Array[Byte]): String = { 40 | MessageDigest.getInstance("SHA-1").digest(bytes).map("%02x".format(_)).mkString 41 | } 42 | 43 | /** 44 | * Creates a SHA2 hash from the given string. 45 | * 46 | * @param str The string to create a hash from. 47 | * @return The SHA2 hash of the string. 48 | */ 49 | def sha2(str: String): String = sha2(str.getBytes("UTF-8")) 50 | 51 | /** 52 | * Creates a SHA2 hash from the given byte array. 53 | * 54 | * @param bytes The bytes to create a hash from. 55 | * @return The SHA2 hash of the bytes. 56 | */ 57 | def sha2(bytes: Array[Byte]): String = { 58 | MessageDigest.getInstance("SHA-256").digest(bytes).map("%02x".format(_)).mkString 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository is not longer maintained. All the related resources like the documentation and the forum will be closed. 2 | 3 | Silhouette 4 | ========== 5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.mohiva/play-silhouette_2.12/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.mohiva/play-silhouette_2.12) [![Build Status](https://travis-ci.org/mohiva/play-silhouette.png)](https://travis-ci.org/mohiva/play-silhouette) [![Coverage Status](https://coveralls.io/repos/mohiva/play-silhouette/badge.svg?branch=master&service=github)](https://coveralls.io/github/mohiva/play-silhouette?branch=master) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mohiva/play-silhouette?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | [![OpenCollective](https://opencollective.com/silhouette/backers/badge.svg)](#backers) 7 | [![OpenCollective](https://opencollective.com/silhouette/sponsors/badge.svg)](#sponsors) 8 | 9 | 10 | **Silhouette** is an authentication library for Play Framework applications that supports several authentication methods, including OAuth1, OAuth2, OpenID, CAS, Credentials, Basic Authentication, Two Factor Authentication or custom authentication schemes. 11 | 12 | See [the project documentation] for more information. 13 | 14 | ## Support 15 | 16 | If you have question regarding Silhouette, please use the [chat] or the [forum]. **Please do not use the issue tracker for questions!** 17 | 18 | ## Contribution 19 | 20 | Please read the [contributing guide] before you contribute. It contains very useful tips for a successful contribution. 21 | 22 | ## License 23 | 24 | The code is licensed under [Apache License v2.0] and the documentation under [CC BY 3.0]. 25 | 26 | [the project documentation]: http://www.silhouette.rocks/docs 27 | [chat]: https://gitter.im/mohiva/play-silhouette 28 | [forum]: http://discourse.silhouette.rocks/ 29 | [contributing guide]: CONTRIBUTING.md 30 | [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0 31 | [CC BY 3.0]: http://creativecommons.org/licenses/by/3.0/ 32 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/repositories/AuthenticatorRepository.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.repositories 17 | 18 | import com.mohiva.play.silhouette.api.StorableAuthenticator 19 | 20 | import scala.concurrent.Future 21 | 22 | /** 23 | * A trait that provides the means to persist authenticator information for the Silhouette module. 24 | * 25 | * @tparam T The type of the authenticator to store. 26 | */ 27 | trait AuthenticatorRepository[T <: StorableAuthenticator] { 28 | 29 | /** 30 | * Finds the authenticator for the given ID. 31 | * 32 | * @param id The authenticator ID. 33 | * @return The found authenticator or None if no authenticator could be found for the given ID. 34 | */ 35 | def find(id: String): Future[Option[T]] 36 | 37 | /** 38 | * Adds a new authenticator. 39 | * 40 | * @param authenticator The authenticator to add. 41 | * @return The added authenticator. 42 | */ 43 | def add(authenticator: T): Future[T] 44 | 45 | /** 46 | * Updates an already existing authenticator. 47 | * 48 | * @param authenticator The authenticator to update. 49 | * @return The updated authenticator. 50 | */ 51 | def update(authenticator: T): Future[T] 52 | 53 | /** 54 | * Removes the authenticator for the given ID. 55 | * 56 | * @param id The authenticator ID. 57 | * @return An empty future. 58 | */ 59 | def remove(id: String): Future[Unit] 60 | } 61 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/Provider.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | import play.api.mvc.Request 19 | 20 | import scala.concurrent.Future 21 | 22 | /** 23 | * A marker interface for all providers. 24 | */ 25 | trait Provider { 26 | 27 | /** 28 | * Gets the provider ID. 29 | * 30 | * @return The provider ID. 31 | */ 32 | def id: String 33 | } 34 | 35 | /** 36 | * A provider which can be hooked into a request. 37 | * 38 | * It scans the request for credentials and returns the login info for it. 39 | */ 40 | trait RequestProvider extends Provider { 41 | 42 | /** 43 | * Authenticates an identity based on credentials sent in a request. 44 | * 45 | * Silhouette supports chaining of request providers. So if more as one request provider is defined 46 | * it tries to authenticate until one provider returns an identity. To control the behaviour of the 47 | * chaining you can use the return type by this method. 48 | * 49 | * None - If returning None, then the next provider in the chain will be executed. 50 | * Some(identity) - If returning some identity, then this provider will be used for authentication. 51 | * Exception - Throwing an exception breaks the chain. The error handler will also handle this exception. 52 | * 53 | * @param request The request. 54 | * @tparam B The type of the body. 55 | * @return Some login info on successful authentication or None if the authentication was unsuccessful. 56 | */ 57 | def authenticate[B](request: Request[B]): Future[Option[LoginInfo]] 58 | } 59 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/AuthenticatorSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | import com.mohiva.play.silhouette.api.Authenticator.Implicits._ 19 | import org.joda.time.DateTime 20 | import play.api.test.PlaySpecification 21 | 22 | import scala.concurrent.duration._ 23 | 24 | /** 25 | * Test case for the [[com.mohiva.play.silhouette.api.Authenticator]] class. 26 | */ 27 | class AuthenticatorSpec extends PlaySpecification { 28 | 29 | "The + method of the RichDateTime class" should { 30 | "add a second to a DateTime instance" in { 31 | new DateTime(2015, 6, 16, 19, 46, 0) + 1.second must be equalTo new DateTime(2015, 6, 16, 19, 46, 1) 32 | } 33 | 34 | "add a minute to a DateTime instance" in { 35 | new DateTime(2015, 6, 16, 19, 46, 0) + 1.minute must be equalTo new DateTime(2015, 6, 16, 19, 47, 0) 36 | } 37 | 38 | "add an hour to a DateTime instance" in { 39 | new DateTime(2015, 6, 16, 19, 46, 0) + 1.hour must be equalTo new DateTime(2015, 6, 16, 20, 46, 0) 40 | } 41 | 42 | "subtract a second from a DateTime instance" in { 43 | new DateTime(2015, 6, 16, 19, 46, 0) - 1.second must be equalTo new DateTime(2015, 6, 16, 19, 45, 59) 44 | } 45 | 46 | "subtract a minute from a DateTime instance" in { 47 | new DateTime(2015, 6, 16, 19, 46, 0) - 1.minute must be equalTo new DateTime(2015, 6, 16, 19, 45, 0) 48 | } 49 | 50 | "subtract an hour from a DateTime instance" in { 51 | new DateTime(2015, 6, 16, 19, 46, 0) - 1.hour must be equalTo new DateTime(2015, 6, 16, 18, 46, 0) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/api-doc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Updates the API-Doc in the 'gh-pages' branch. 4 | # 5 | # Copyright 2015 Mohiva Organisation (license at mohiva dot com) 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | set -o nounset -o errexit 20 | 21 | if [ "$TRAVIS_REPO_SLUG" == "mohiva/play-silhouette" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then 22 | echo "" 23 | echo "Starting API-Doc update process" 24 | 25 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 26 | GH_PAGES_DIR="$HOME/.sbt/ghpages/com.mohiva/root" 27 | ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_ID}_key" 28 | ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_ID}_iv" 29 | ENCRYPTED_KEY_FILE="${SCRIPTS_DIR}/api-doc.key.enc" 30 | DECRYPTED_KEY_FILE="${SCRIPTS_DIR}/api-doc.key" 31 | ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} 32 | ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} 33 | 34 | openssl aes-256-cbc -K ${ENCRYPTED_KEY} -iv ${ENCRYPTED_IV} -in ${ENCRYPTED_KEY_FILE} -out ${DECRYPTED_KEY_FILE} -d 35 | chmod 600 ${DECRYPTED_KEY_FILE} 36 | 37 | printf "%s\n" \ 38 | "Host github.com" \ 39 | " HostName github.com" \ 40 | " IdentityFile ${DECRYPTED_KEY_FILE}" \ 41 | " IdentitiesOnly yes" \ 42 | >> ~/.ssh/config 43 | 44 | rm -rf "$(dirname ${GH_PAGES_DIR})" 45 | mkdir -p "$(dirname ${GH_PAGES_DIR})" 46 | git clone --quiet --branch=gh-pages git@github.com:${TRAVIS_REPO_SLUG}.git "$GH_PAGES_DIR" > /dev/null 47 | git config --global user.email "travis@travis-ci.org" 48 | git config --global user.name "travis-ci" 49 | git config --global push.default simple 50 | 51 | scripts/sbt ghpages-push-site 52 | 53 | echo "" 54 | echo "Finished API-Doc update process" 55 | else 56 | echo "" 57 | echo "Skipping API-Doc update" 58 | fi 59 | -------------------------------------------------------------------------------- /project/Dependencies.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import sbt._ 17 | 18 | object Dependencies { 19 | val resolvers = Seq( 20 | "Atlassian Releases" at "https://maven.atlassian.com/public/" 21 | ) 22 | 23 | object Library { 24 | 25 | object Play { 26 | val version = play.core.PlayVersion.current 27 | val ws = "com.typesafe.play" %% "play-ws" % version 28 | val cache = "com.typesafe.play" %% "play-cache" % version 29 | val test = "com.typesafe.play" %% "play-test" % version 30 | val specs2 = "com.typesafe.play" %% "play-specs2" % version 31 | val openid = "com.typesafe.play" %% "play-openid" % version 32 | val jsonJoda = "com.typesafe.play" %% "play-json-joda" % "2.7.4" 33 | } 34 | 35 | object Specs2 { 36 | private val version = "4.5.1" 37 | val core = "org.specs2" %% "specs2-core" % version 38 | val matcherExtra = "org.specs2" %% "specs2-matcher-extra" % version 39 | val mock = "org.specs2" %% "specs2-mock" % version 40 | } 41 | 42 | val jbcrypt = "de.svenkubiak" % "jBCrypt" % "0.4.1" 43 | val jwtCore = "com.atlassian.jwt" % "jwt-core" % "2.0.5" 44 | val jwtApi = "com.atlassian.jwt" % "jwt-api" % "2.0.5" 45 | val scalaGuice = "net.codingwell" %% "scala-guice" % "4.2.5" 46 | val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % "2.6.3" 47 | val casClient = "org.jasig.cas.client" % "cas-client-core" % "3.4.1" 48 | val casClientSupportSAML = "org.jasig.cas.client" % "cas-client-support-saml" % "3.4.1" 49 | val apacheCommonLang = "org.apache.commons" % "commons-lang3" % "3.8.1" 50 | val googleAuth = "com.warrenstrange" % "googleauth" % "1.2.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /silhouette-crypto-jca/src/test/scala/com/mohiva/play/silhouette/crypto/JcaCrypterSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.crypto 17 | 18 | import com.mohiva.play.silhouette.api.exceptions.CryptoException 19 | import com.mohiva.play.silhouette.crypto.JcaCrypter._ 20 | import org.specs2.mutable.Specification 21 | import org.specs2.specification.Scope 22 | 23 | /** 24 | * Test case for the [[JcaCrypter]] class. 25 | */ 26 | class JcaCrypterSpec extends Specification { 27 | 28 | "The `decrypt` method" should { 29 | "throw a CryptoException if the format is unexpected" in new Context { 30 | encoder.decrypt("data") must throwA[CryptoException].like { 31 | case e => 32 | e.getMessage must be equalTo UnexpectedFormat 33 | } 34 | } 35 | 36 | "throw a CryptoException if the version is unknown" in new Context { 37 | encoder.decrypt("2-data") must throwA[CryptoException].like { 38 | case e => 39 | e.getMessage must be equalTo UnknownVersion.format(2) 40 | } 41 | } 42 | } 43 | 44 | "The crypter" should { 45 | "encrypt/decrypt a string" in new Context { 46 | val text = "Silhouette rocks" 47 | encoder.decrypt(encoder.encrypt(text)) must be equalTo text 48 | } 49 | } 50 | 51 | /** 52 | * The context. 53 | */ 54 | trait Context extends Scope { 55 | 56 | /** 57 | * The encryption key. 58 | */ 59 | val key = "s3cr3t_k3y" 60 | 61 | /** 62 | * The settings instance. 63 | */ 64 | val settings = new JcaCrypterSettings(key) 65 | 66 | /** 67 | * The crypter to test. 68 | */ 69 | val encoder = new JcaCrypter(settings) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/PasswordProviderSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers 17 | 18 | import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository 19 | import com.mohiva.play.silhouette.api.util._ 20 | import org.specs2.mock.Mockito 21 | import org.specs2.specification.Scope 22 | import play.api.test.PlaySpecification 23 | 24 | /** 25 | * Abstract test case for the [[com.mohiva.play.silhouette.impl.providers.PasswordProvider]] based class. 26 | */ 27 | trait PasswordProviderSpec extends PlaySpecification with Mockito { 28 | 29 | /** 30 | * The context. 31 | */ 32 | trait BaseContext extends Scope { 33 | 34 | /** 35 | * The default password hasher. 36 | */ 37 | lazy val fooHasher = hasher("foo") 38 | 39 | /** 40 | * A deprecated password hasher. 41 | */ 42 | lazy val barHasher = hasher("bar") 43 | 44 | /** 45 | * The auth info repository mock. 46 | */ 47 | lazy val authInfoRepository = mock[AuthInfoRepository] 48 | 49 | /** 50 | * The password hasher registry. 51 | */ 52 | lazy val passwordHasherRegistry = new PasswordHasherRegistry(fooHasher, Seq(barHasher)) 53 | 54 | /** 55 | * Helper method to create a hasher mock. 56 | * 57 | * @param id The ID of the hasher. 58 | * @return A hasher mock. 59 | */ 60 | private def hasher(id: String) = { 61 | val h = mock[PasswordHasher] 62 | h.id returns id 63 | h.isSuitable(any()) answers { p: Any => 64 | p.asInstanceOf[PasswordInfo].hasher == h.id 65 | } 66 | h.isDeprecated(any()) returns Some(false) 67 | h 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/util/PlayCacheLayer.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.util 17 | 18 | import javax.inject.Inject 19 | 20 | import com.mohiva.play.silhouette.api.util.CacheLayer 21 | import play.api.cache.AsyncCacheApi 22 | 23 | import scala.concurrent.Future 24 | import scala.concurrent.duration.Duration 25 | import scala.reflect.ClassTag 26 | 27 | /** 28 | * Implementation of the cache layer which uses the default Play cache plugin. 29 | * 30 | * @param cacheApi Plays cache API implementation. 31 | */ 32 | class PlayCacheLayer @Inject() (cacheApi: AsyncCacheApi) extends CacheLayer { 33 | 34 | /** 35 | * Save a value in cache. 36 | * 37 | * @param key The item key under which the value should be saved. 38 | * @param value The value to save. 39 | * @param expiration Expiration time in seconds (0 second means eternity). 40 | * @return The value saved in cache. 41 | */ 42 | override def save[T](key: String, value: T, expiration: Duration = Duration.Inf): Future[T] = Future.successful { 43 | cacheApi.set(key, value, expiration) 44 | value 45 | } 46 | 47 | /** 48 | * Finds a value in the cache. 49 | * 50 | * @param key The key of the item to found. 51 | * @tparam T The type of the object to return. 52 | * @return The found value or None if no value could be found. 53 | */ 54 | override def find[T: ClassTag](key: String): Future[Option[T]] = cacheApi.get[T](key) 55 | 56 | /** 57 | * Remove a value from the cache. 58 | * 59 | * @param key Item key. 60 | * @return An empty future to wait for removal. 61 | */ 62 | override def remove(key: String) = Future.successful(cacheApi.remove(key)) 63 | } 64 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/util/PlayCacheLayerSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.util 17 | 18 | import org.joda.time.DateTime 19 | import org.specs2.mock.Mockito 20 | import org.specs2.specification.Scope 21 | import play.api.cache.AsyncCacheApi 22 | import play.api.test.PlaySpecification 23 | 24 | import scala.concurrent.Future 25 | import scala.concurrent.duration.Duration 26 | 27 | /** 28 | * Test case for the [[com.mohiva.play.silhouette.impl.util.PlayCacheLayer]] class. 29 | */ 30 | class PlayCacheLayerSpec extends PlaySpecification with Mockito { 31 | 32 | "The `find` method" should { 33 | "return value from cache" in new Context { 34 | cacheAPI.get[DateTime]("id") returns Future.successful(Some(value)) 35 | 36 | await(layer.find[DateTime]("id")) should beSome(value) 37 | 38 | there was one(cacheAPI).get[DateTime]("id") 39 | } 40 | } 41 | 42 | "The `save` method" should { 43 | "save value in cache" in new Context { 44 | await(layer.save("id", value)) 45 | 46 | there was one(cacheAPI).set("id", value, Duration.Inf) 47 | } 48 | } 49 | 50 | "The `remove` method" should { 51 | "removes value from cache" in new Context { 52 | await(layer.remove("id")) must beEqualTo(()) 53 | 54 | there was one(cacheAPI).remove("id") 55 | } 56 | } 57 | 58 | /** 59 | * The context. 60 | */ 61 | trait Context extends Scope { 62 | 63 | /** 64 | * The cache API. 65 | */ 66 | lazy val cacheAPI = mock[AsyncCacheApi] 67 | 68 | /** 69 | * The layer to test. 70 | */ 71 | lazy val layer = new PlayCacheLayer(cacheAPI) 72 | 73 | /** 74 | * The value to cache. 75 | */ 76 | lazy val value = new DateTime 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/api/services/AuthenticatorResultSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.services 17 | 18 | import play.api.mvc.{ Cookie, Results } 19 | import play.api.test.{ WithApplication, PlaySpecification } 20 | 21 | /** 22 | * Test case for the [[com.mohiva.play.silhouette.api.services.AuthenticatorResult]] class. 23 | */ 24 | class AuthenticatorResultSpec extends PlaySpecification { 25 | 26 | "The `copy` method" should { 27 | "return new a new instance of an authenticator result" in { 28 | val result = Results.Ok 29 | val authenticatorResult = AuthenticatorResult(result) 30 | 31 | authenticatorResult.copy(result.header, result.body) must beAnInstanceOf[AuthenticatorResult] 32 | } 33 | } 34 | 35 | "The `withSession` method" should { 36 | "return new a new instance of an authenticator result" in new WithApplication { 37 | val result = Results.Ok 38 | val authenticatorResult = AuthenticatorResult(result) 39 | 40 | authenticatorResult.withSession("name" -> "value") must beAnInstanceOf[AuthenticatorResult] 41 | } 42 | } 43 | 44 | "The `withCookies` method" should { 45 | "return new a new instance of an authenticator result" in new WithApplication { 46 | val result = Results.Ok 47 | val authenticatorResult = AuthenticatorResult(result) 48 | 49 | authenticatorResult.withCookies(Cookie("name", "value")) must beAnInstanceOf[AuthenticatorResult] 50 | } 51 | } 52 | 53 | "The `withHeaders` method" should { 54 | "return new a new instance of an authenticator result" in new WithApplication { 55 | val result = Results.Ok 56 | val authenticatorResult = AuthenticatorResult(result) 57 | 58 | authenticatorResult.withHeaders("name" -> "value") must beAnInstanceOf[AuthenticatorResult] 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/util/SecureRandomIDGenerator.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.impl.util 21 | 22 | import java.security.SecureRandom 23 | 24 | import com.mohiva.play.silhouette.api.util.IDGenerator 25 | import play.api.libs.Codecs 26 | 27 | import scala.concurrent.{ ExecutionContext, Future } 28 | 29 | /** 30 | * A generator which uses SecureRandom to generate cryptographically strong IDs. 31 | * 32 | * @param idSizeInBytes The size of the ID length in bytes. 33 | * @param ec The execution context to handle the asynchronous operations. 34 | */ 35 | class SecureRandomIDGenerator(idSizeInBytes: Int = 128)(implicit ec: ExecutionContext) extends IDGenerator { 36 | 37 | /** 38 | * Generates a new ID using SecureRandom. 39 | * 40 | * @return The generated ID. 41 | */ 42 | override def generate: Future[String] = { 43 | val randomValue = new Array[Byte](idSizeInBytes) 44 | Future(SecureRandomIDGenerator.random.nextBytes(randomValue)).map { _ => 45 | Codecs.toHexString(randomValue) 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * The companion object. 52 | */ 53 | object SecureRandomIDGenerator { 54 | 55 | /** 56 | * A cryptographically strong random number generator (RNG). 57 | * 58 | * There is a cost of getting a secure random instance for its initial seeding, so it's recommended you use 59 | * a singleton style so you only create one for all of your usage going forward. 60 | * 61 | * On Linux systems SecureRandom uses /dev/random and it can block waiting for sufficient entropy to build up. 62 | */ 63 | lazy val random = new SecureRandom() 64 | } 65 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Silhouette 2 | ========================== 3 | 4 | How to contribute 5 | ----------------- 6 | 7 | Silhouette is an open source project. Contributions are appreciated. 8 | 9 | Some ways in which you can contribute are: reporting errors, improving documentation, adding examples, adding support 10 | for more services, fixing bugs, suggesting new features, adding test cases, translating messages, and whatever else 11 | you can think of that may be helpful. If in doubt, just ask. 12 | 13 | 14 | Development workflow 15 | -------------------- 16 | 17 | Development is coordinated via [GitHub]. Ideas for improvements are discussed using the [chat] or the [mailing list]. 18 | 19 | To submit issues, please use the [GitHub issue tracker]. **Please do not use the issue tracker for questions!** 20 | 21 | The documentation can be improved by submitting change requests via [readme.io]. 22 | 23 | For a more streamlined experience for all people involved, we encourage contributors to follow the practices described 24 | at [GitHub workflow for submitting pull requests]. 25 | 26 | Scala source code should follow the conventions documented in the [Scala Style Guide]. Additionally, acronyms should 27 | be capitalized. To have your code automatically reformatted, run this command before committing your changes: 28 | 29 | scripts/reformat 30 | 31 | After submitting your pull request, please [watch the result] of the automated Travis CI build and correct any reported 32 | errors or inconsistencies. 33 | 34 | 35 | License and Copyright 36 | --------------------- 37 | 38 | By submitting work via pull requests, issues, documentation, or any other means, contributors indicate their agreement to 39 | publish their work under this project's license and also attest that they are the authors of the work and grant a 40 | copyright license to the Mohiva Organisation, unless the contribution clearly states a different copyright notice 41 | (e.g., it contains original work by a third party). 42 | 43 | 44 | [GitHub]: https://github.com/mohiva/play-silhouette 45 | [GitHub issue tracker]: https://github.com/mohiva/play-silhouette/issues 46 | [GitHub workflow for submitting pull requests]: https://www.playframework.com/documentation/2.5.x/WorkingWithGit 47 | [chat]: https://gitter.im/mohiva/play-silhouette 48 | [mailing list]: https://groups.google.com/forum/#!forum/play-silhouette 49 | [Scala Style Guide]: http://docs.scala-lang.org/style/ 50 | [watch the result]: https://travis-ci.org/mohiva/play-silhouette/pull_requests 51 | [readme.io]: http://silhouette.mohiva.com/ 52 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/util/DefaultFingerprintGenerator.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.impl.util 21 | 22 | import com.mohiva.play.silhouette.api.crypto.Hash 23 | import com.mohiva.play.silhouette.api.util.FingerprintGenerator 24 | import play.api.http.HeaderNames._ 25 | import play.api.mvc.RequestHeader 26 | 27 | /** 28 | * A generator which creates a SHA1 fingerprint from `User-Agent`, `Accept-Language`, `Accept-Charset` 29 | * and `Accept-Encoding` headers and if defined the remote address of the user. 30 | * 31 | * The `Accept` header would also be a good candidate, but this header makes problems in applications 32 | * which uses content negotiation. So the default fingerprint generator doesn't include it. 33 | * 34 | * The same with `Accept-Encoding`. But in Chromium/Blink based browser the content of this header may 35 | * be changed during requests. @see https://github.com/mohiva/play-silhouette/issues/277 36 | * 37 | * @param includeRemoteAddress Indicates if the remote address should be included into the fingerprint. 38 | */ 39 | class DefaultFingerprintGenerator(includeRemoteAddress: Boolean = false) extends FingerprintGenerator { 40 | 41 | /** 42 | * Generates a fingerprint from request. 43 | * 44 | * @param request The request header. 45 | * @return The generated fingerprint. 46 | */ 47 | override def generate(implicit request: RequestHeader) = { 48 | Hash.sha1(new StringBuilder() 49 | .append(request.headers.get(USER_AGENT).getOrElse("")).append(":") 50 | .append(request.headers.get(ACCEPT_LANGUAGE).getOrElse("")).append(":") 51 | .append(request.headers.get(ACCEPT_CHARSET).getOrElse("")).append(":") 52 | .append(if (includeRemoteAddress) request.remoteAddress else "") 53 | .toString() 54 | ) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/repositories/CacheAuthenticatorRepository.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence.repositories 17 | 18 | import javax.inject.Inject 19 | 20 | import com.mohiva.play.silhouette.api.StorableAuthenticator 21 | import com.mohiva.play.silhouette.api.repositories.AuthenticatorRepository 22 | import com.mohiva.play.silhouette.api.util.CacheLayer 23 | 24 | import scala.concurrent.Future 25 | import scala.concurrent.duration.Duration 26 | import scala.reflect.ClassTag 27 | 28 | /** 29 | * Implementation of the authenticator repository which uses the cache layer to persist the authenticator. 30 | * 31 | * @param cacheLayer The cache layer implementation. 32 | * @tparam T The type of the authenticator to store. 33 | */ 34 | class CacheAuthenticatorRepository[T <: StorableAuthenticator: ClassTag] @Inject() (cacheLayer: CacheLayer) 35 | extends AuthenticatorRepository[T] { 36 | 37 | /** 38 | * Finds the authenticator for the given ID. 39 | * 40 | * @param id The authenticator ID. 41 | * @return The found authenticator or None if no authenticator could be found for the given ID. 42 | */ 43 | override def find(id: String): Future[Option[T]] = cacheLayer.find[T](id) 44 | 45 | /** 46 | * Adds a new authenticator. 47 | * 48 | * @param authenticator The authenticator to add. 49 | * @return The added authenticator. 50 | */ 51 | override def add(authenticator: T): Future[T] = cacheLayer.save[T](authenticator.id, authenticator, Duration.Inf) 52 | 53 | /** 54 | * Updates an already existing authenticator. 55 | * 56 | * @param authenticator The authenticator to update. 57 | * @return The updated authenticator. 58 | */ 59 | override def update(authenticator: T): Future[T] = cacheLayer.save[T](authenticator.id, authenticator, Duration.Inf) 60 | 61 | /** 62 | * Removes the authenticator for the given ID. 63 | * 64 | * @param id The authenticator ID. 65 | * @return An empty future. 66 | */ 67 | override def remove(id: String): Future[Unit] = cacheLayer.remove(id) 68 | } 69 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/daos/AuthInfoDAO.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence.daos 17 | 18 | import com.mohiva.play.silhouette.api.{ AuthInfo, LoginInfo } 19 | 20 | import scala.concurrent.Future 21 | 22 | /** 23 | * The DAO to persist the auth info. 24 | * 25 | * @tparam T The type of the auth info to store. 26 | */ 27 | trait AuthInfoDAO[T <: AuthInfo] { 28 | 29 | /** 30 | * Finds the auth info which is linked to the specified login info. 31 | * 32 | * @param loginInfo The linked login info. 33 | * @return The found auth info or None if no auth info could be found for the given login info. 34 | */ 35 | def find(loginInfo: LoginInfo): Future[Option[T]] 36 | 37 | /** 38 | * Adds new auth info for the given login info. 39 | * 40 | * @param loginInfo The login info for which the auth info should be added. 41 | * @param authInfo The auth info to add. 42 | * @return The added auth info. 43 | */ 44 | def add(loginInfo: LoginInfo, authInfo: T): Future[T] 45 | 46 | /** 47 | * Updates the auth info for the given login info. 48 | * 49 | * @param loginInfo The login info for which the auth info should be updated. 50 | * @param authInfo The auth info to update. 51 | * @return The updated auth info. 52 | */ 53 | def update(loginInfo: LoginInfo, authInfo: T): Future[T] 54 | 55 | /** 56 | * Saves the auth info for the given login info. 57 | * 58 | * This method either adds the auth info if it doesn't exists or it updates the auth info 59 | * if it already exists. 60 | * 61 | * @param loginInfo The login info for which the auth info should be saved. 62 | * @param authInfo The auth info to save. 63 | * @return The saved auth info. 64 | */ 65 | def save(loginInfo: LoginInfo, authInfo: T): Future[T] 66 | 67 | /** 68 | * Removes the auth info for the given login info. 69 | * 70 | * @param loginInfo The login info for which the auth info should be removed. 71 | * @return A future to wait for the process to be completed. 72 | */ 73 | def remove(loginInfo: LoginInfo): Future[Unit] 74 | } 75 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/util/HTTPLayer.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.util 17 | 18 | import play.api.libs.ws._ 19 | 20 | import scala.concurrent.ExecutionContext 21 | 22 | /** 23 | * A trait which provides a mockable implementation for the HTTP layer. 24 | */ 25 | trait HTTPLayer extends ExecutionContextProvider { 26 | 27 | /** 28 | * The type of the request. 29 | */ 30 | type Request <: WSRequest 31 | 32 | /** 33 | * Prepare a new request. You can then construct it by chaining calls. 34 | * 35 | * @param url The URL to request. 36 | */ 37 | def url(url: String): Request 38 | } 39 | 40 | /** 41 | * Implementation of the HTTP layer which uses the Play web service implementation. 42 | * 43 | * It makes no sense to move the HTTPLayer implementation to the contrib package, because the complete 44 | * Silhouette module is bound to Play's HTTP implementation. So this layer exists only for mocking purpose. 45 | * 46 | * @param client Play's WS client implementation. 47 | * @param executionContext The execution context to handle the asynchronous operations. 48 | */ 49 | class PlayHTTPLayer(client: WSClient)(implicit val executionContext: ExecutionContext) extends HTTPLayer { 50 | 51 | /** 52 | * The type of the request. 53 | */ 54 | type Request = WSRequest 55 | 56 | /** 57 | * Prepare a new request. You can then construct it by chaining calls. 58 | * 59 | * @param url The URL to request. 60 | */ 61 | def url(url: String): Request = client.url(url) 62 | } 63 | 64 | /** 65 | * A mockable WS request. 66 | * 67 | * @see https://github.com/playframework/play-ws/issues/108 68 | */ 69 | trait MockWSRequest extends WSRequest { 70 | override type Self = WSRequest 71 | override type Response = WSResponse 72 | } 73 | 74 | /** 75 | * A mockable HTTP layer. 76 | */ 77 | trait MockHTTPLayer extends HTTPLayer { 78 | 79 | /** 80 | * The type of the request. 81 | */ 82 | type Request = MockWSRequest 83 | 84 | /** 85 | * Prepare a new request. You can then construct it by chaining calls. 86 | * 87 | * @param url The URL to request. 88 | */ 89 | def url(url: String): Request 90 | } 91 | -------------------------------------------------------------------------------- /silhouette-crypto-jca/src/test/scala/com/mohiva/play/silhouette/crypto/JcaSignerSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.crypto 17 | 18 | import java.util.regex.Pattern 19 | 20 | import org.specs2.mutable.Specification 21 | import org.specs2.specification.Scope 22 | import JcaSigner._ 23 | import com.mohiva.play.silhouette.api.exceptions.CryptoException 24 | 25 | /** 26 | * Test case for the [[JcaSigner]] class. 27 | */ 28 | class JcaSignerSpec extends Specification { 29 | 30 | "The `sign` method" should { 31 | "return a signed message in the form [VERSION]-[SIGNATURE]-[DATA]" in new Context { 32 | val data = "some-data" 33 | 34 | signer.sign(data) must beMatching(s"1-[^-]+-$data") 35 | } 36 | } 37 | 38 | "The `extract` method" should { 39 | "throw a `CryptoException` if the message format is invalid" in new Context { 40 | val msg = "^" + Pattern.quote(InvalidMessageFormat) + ".*" 41 | 42 | signer.extract("invalid") must beFailedTry.withThrowable[CryptoException](msg) 43 | } 44 | 45 | "throw a `CryptoException` if the version is unknown" in new Context { 46 | val msg = "^" + Pattern.quote(UnknownVersion.format(2)) + ".*" 47 | 48 | signer.extract("2-signature-data") must beFailedTry.withThrowable[CryptoException](msg) 49 | } 50 | 51 | "throw a `CryptoException` if the signature is invalid" in new Context { 52 | val msg = "^" + Pattern.quote(BadSignature) + ".*" 53 | 54 | signer.extract("1-signature-data") must beFailedTry.withThrowable[CryptoException](msg) 55 | } 56 | 57 | "extract a previously signed message" in new Context { 58 | val data = "some-data" 59 | val message = signer.sign(data) 60 | 61 | signer.extract(message) must beSuccessfulTry.withValue(data) 62 | } 63 | } 64 | 65 | /** 66 | * The context. 67 | */ 68 | trait Context extends Scope { 69 | 70 | /** 71 | * The encryption key. 72 | */ 73 | val key = "s3cr3t_k3y" 74 | 75 | /** 76 | * The settings instance. 77 | */ 78 | val settings = JcaSignerSettings(key) 79 | 80 | /** 81 | * The cookie signer to test. 82 | */ 83 | val signer = new JcaSigner(settings) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /silhouette-testkit/app/com/mohiva/play/silhouette/test/package.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette 17 | 18 | import com.mohiva.play.silhouette.api._ 19 | import play.api.mvc.Request 20 | import play.api.test.FakeRequest 21 | 22 | import scala.concurrent.duration._ 23 | import scala.concurrent.{ Await, Future } 24 | import scala.language.{ implicitConversions, postfixOps } 25 | 26 | /** 27 | * Test helpers to test a Silhouette application. 28 | */ 29 | package object test { 30 | 31 | /** 32 | * Resolves a future by waiting of the result. 33 | * 34 | * @param f The future to block. 35 | * @tparam T The type contained in the future. 36 | * @return The value contained in the future. 37 | */ 38 | implicit protected[test] def await[T](f: Future[T]): T = Await.result(f, 60 seconds) 39 | 40 | /** 41 | * Provides a method which add an authenticator to a fake request. 42 | * 43 | * @param f A fake request instance. 44 | * @tparam A The type of the body. 45 | */ 46 | implicit class FakeRequestWithAuthenticator[A](f: FakeRequest[A]) { 47 | implicit val request = f 48 | 49 | /** 50 | * Creates a fake request with an embedded authenticator. 51 | * 52 | * @param authenticator The authenticator to embed into the request. 53 | * @param env The Silhouette environment. 54 | * @tparam E The type of the environment. 55 | * @return A fake request. 56 | */ 57 | def withAuthenticator[E <: Env](authenticator: E#A)(implicit env: Environment[E]): FakeRequest[A] = { 58 | implicit val ec = env.executionContext 59 | val rh = env.authenticatorService.init(authenticator).map(v => env.authenticatorService.embed(v, f)) 60 | 61 | new FakeRequest(Request.apply(rh, f.body)) 62 | } 63 | 64 | /** 65 | * Creates a fake request with an embedded authenticator. 66 | * 67 | * @param loginInfo The login info for which the new authenticator should be created. 68 | * @param env The Silhouette environment. 69 | * @tparam E The type of the environment. 70 | * @return A fake request. 71 | */ 72 | def withAuthenticator[E <: Env](loginInfo: LoginInfo)(implicit env: Environment[E]): FakeRequest[A] = { 73 | withAuthenticator(FakeAuthenticator[E](loginInfo)) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/openid/SteamProviderSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers.openid 17 | 18 | import com.mohiva.play.silhouette.api.LoginInfo 19 | import com.mohiva.play.silhouette.impl.providers._ 20 | import play.api.test.WithApplication 21 | 22 | /** 23 | * Test case for the [[SteamProvider]] class. 24 | */ 25 | class SteamProviderSpec extends OpenIDProviderSpec { 26 | 27 | "The `withSettings` method" should { 28 | "create a new instance with customized settings" in new WithApplication with Context { 29 | val overrideSettingsFunction: OpenIDSettings => OpenIDSettings = { s => 30 | s.copy("new-provider-url") 31 | } 32 | val s = provider.withSettings(overrideSettingsFunction) 33 | 34 | s.settings.providerURL must be equalTo "new-provider-url" 35 | there was one(openIDService).withSettings(overrideSettingsFunction) 36 | } 37 | } 38 | 39 | "The `retrieveProfile` method" should { 40 | "return the social profile" in new WithApplication with Context { 41 | profile(provider.retrieveProfile(openIDInfo)) { 42 | case p => p must be equalTo new CommonSocialProfile( 43 | loginInfo = LoginInfo(provider.id, "http://steamcommunity.com/openid/id/16261495063738643") 44 | ) 45 | } 46 | } 47 | } 48 | 49 | /** 50 | * Defines the context for the abstract OpenID provider spec. 51 | * 52 | * @return The Context to use for the abstract OpenID provider spec. 53 | */ 54 | override protected def context: OpenIDProviderSpecContext = new Context {} 55 | 56 | /** 57 | * The context. 58 | */ 59 | trait Context extends OpenIDProviderSpecContext { 60 | 61 | /** 62 | * A OpenID info. 63 | */ 64 | override lazy val openIDInfo = OpenIDInfo("http://steamcommunity.com/openid/id/16261495063738643", Map()) 65 | 66 | /** 67 | * The OpenID settings. 68 | */ 69 | lazy val openIDSettings = spy(OpenIDSettings( 70 | providerURL = "https://steamcommunity.com/openid/", 71 | callbackURL = "http://localhost:9000/authenticate/steam", 72 | realm = Some("http://localhost:9000") 73 | )) 74 | 75 | /** 76 | * The provider to test. 77 | */ 78 | lazy val provider = new SteamProvider(httpLayer, openIDService, openIDSettings) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/util/DefaultFingerprintGeneratorSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.util 17 | 18 | import com.mohiva.play.silhouette.api.crypto.Hash 19 | import play.api.test.{ FakeRequest, PlaySpecification } 20 | 21 | /** 22 | * Test case for the [[com.mohiva.play.silhouette.impl.util.DefaultFingerprintGenerator]] class. 23 | */ 24 | class DefaultFingerprintGeneratorSpec extends PlaySpecification { 25 | 26 | "The generator" should { 27 | "return fingerprint including the `User-Agent` header" in { 28 | val userAgent = "test-user-agent" 29 | val generator = new DefaultFingerprintGenerator() 30 | implicit val request = FakeRequest().withHeaders(USER_AGENT -> userAgent) 31 | 32 | generator.generate must be equalTo Hash.sha1(userAgent + ":::") 33 | } 34 | 35 | "return fingerprint including the `Accept-Language` header" in { 36 | val acceptLanguage = "test-accept-language" 37 | val generator = new DefaultFingerprintGenerator() 38 | implicit val request = FakeRequest().withHeaders(ACCEPT_LANGUAGE -> acceptLanguage) 39 | 40 | generator.generate must be equalTo Hash.sha1(":" + acceptLanguage + "::") 41 | } 42 | 43 | "return fingerprint including the `Accept-Charset` header" in { 44 | val acceptCharset = "test-accept-charset" 45 | val generator = new DefaultFingerprintGenerator() 46 | implicit val request = FakeRequest().withHeaders(ACCEPT_CHARSET -> acceptCharset) 47 | 48 | generator.generate must be equalTo Hash.sha1("::" + acceptCharset + ":") 49 | } 50 | 51 | "return fingerprint including the remote address" in { 52 | val generator = new DefaultFingerprintGenerator(true) 53 | implicit val request = FakeRequest() 54 | 55 | generator.generate must be equalTo Hash.sha1(":::127.0.0.1") 56 | } 57 | 58 | "return fingerprint including all values" in { 59 | val userAgent = "test-user-agent" 60 | val acceptLanguage = "test-accept-language" 61 | val acceptCharset = "test-accept-charset" 62 | val generator = new DefaultFingerprintGenerator(true) 63 | implicit val request = FakeRequest().withHeaders( 64 | USER_AGENT -> userAgent, 65 | ACCEPT_LANGUAGE -> acceptLanguage, 66 | ACCEPT_CHARSET -> acceptCharset 67 | ) 68 | 69 | generator.generate must be equalTo Hash.sha1( 70 | userAgent + ":" + acceptLanguage + ":" + acceptCharset + ":127.0.0.1" 71 | ) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/repositories/AuthInfoRepository.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api.repositories 17 | 18 | import com.mohiva.play.silhouette.api.{ AuthInfo, LoginInfo } 19 | 20 | import scala.concurrent.Future 21 | import scala.reflect.ClassTag 22 | 23 | /** 24 | * A trait that provides the means to persist authentication information for the Silhouette module. 25 | * 26 | * If the application supports the concept of "merged identities", i.e., the same user being 27 | * able to authenticate through different providers, then make sure that the auth info for 28 | * every linked login info gets stored separately. 29 | */ 30 | trait AuthInfoRepository { 31 | 32 | /** 33 | * Finds the auth info which is linked with the specified login info. 34 | * 35 | * @param loginInfo The linked login info. 36 | * @param tag The class tag of the auth info. 37 | * @tparam T The type of the auth info to handle. 38 | * @return The found auth info or None if no auth info could be found for the given login info. 39 | */ 40 | def find[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Option[T]] 41 | 42 | /** 43 | * Adds new auth info for the given login info. 44 | * 45 | * @param loginInfo The login info for which the auth info should be saved. 46 | * @param authInfo The auth info to save. 47 | * @tparam T The type of the auth info to handle. 48 | * @return The saved auth info. 49 | */ 50 | def add[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[T] 51 | 52 | /** 53 | * Updates the auth info for the given login info. 54 | * 55 | * @param loginInfo The login info for which the auth info should be updated. 56 | * @param authInfo The auth info to update. 57 | * @tparam T The type of the auth info to handle. 58 | * @return The updated auth info. 59 | */ 60 | def update[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[T] 61 | 62 | /** 63 | * Saves the auth info for the given login info. 64 | * 65 | * This method either adds the auth info if it doesn't exists or it updates the auth info 66 | * if it already exists. 67 | * 68 | * @param loginInfo The login info for which the auth info should be saved. 69 | * @param authInfo The auth info to save. 70 | * @tparam T The type of the auth info to handle. 71 | * @return The updated auth info. 72 | */ 73 | def save[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[T] 74 | 75 | /** 76 | * Removes the auth info for the given login info. 77 | * 78 | * @param loginInfo The login info for which the auth info should be removed. 79 | * @param tag The class tag of the auth info. 80 | * @tparam T The type of the auth info to handle. 81 | * @return A future to wait for the process to be completed. 82 | */ 83 | def remove[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Unit] 84 | } 85 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/openid/YahooProviderSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers.openid 17 | 18 | import com.mohiva.play.silhouette.api.LoginInfo 19 | import com.mohiva.play.silhouette.impl.providers._ 20 | import play.api.test.WithApplication 21 | 22 | /** 23 | * Test case for the [[YahooProvider]] class. 24 | */ 25 | class YahooProviderSpec extends OpenIDProviderSpec { 26 | 27 | "The `withSettings` method" should { 28 | "create a new instance with customized settings" in new WithApplication with Context { 29 | val overrideSettingsFunction: OpenIDSettings => OpenIDSettings = { s => 30 | s.copy("new-provider-url") 31 | } 32 | val s = provider.withSettings(overrideSettingsFunction) 33 | 34 | s.settings.providerURL must be equalTo "new-provider-url" 35 | there was one(openIDService).withSettings(overrideSettingsFunction) 36 | } 37 | } 38 | 39 | "The `retrieveProfile` method" should { 40 | "return the social profile" in new WithApplication with Context { 41 | profile(provider.retrieveProfile(openIDInfo)) { 42 | case p => 43 | p must be equalTo new CommonSocialProfile( 44 | loginInfo = LoginInfo(provider.id, "https://me.yahoo.com/a/Xs6hPjazdrMvmbn4jhQjkjkhcasdGdsKajq9we"), 45 | fullName = Some("Apollonia Vanova"), 46 | email = Some("apollonia.vanova@watchmen.com"), 47 | avatarURL = Some("https://s.yimg.com/dh/ap/social/profile/profile_b48.png") 48 | ) 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * Defines the context for the abstract OpenID provider spec. 55 | * 56 | * @return The Context to use for the abstract OpenID provider spec. 57 | */ 58 | override protected def context: OpenIDProviderSpecContext = new Context {} 59 | 60 | /** 61 | * The context. 62 | */ 63 | trait Context extends OpenIDProviderSpecContext { 64 | 65 | /** 66 | * A OpenID info. 67 | */ 68 | override lazy val openIDInfo = OpenIDInfo("https://me.yahoo.com/a/Xs6hPjazdrMvmbn4jhQjkjkhcasdGdsKajq9we", Map( 69 | "fullname" -> "Apollonia Vanova", 70 | "email" -> "apollonia.vanova@watchmen.com", 71 | "image" -> "https://s.yimg.com/dh/ap/social/profile/profile_b48.png" 72 | )) 73 | 74 | /** 75 | * The OpenID settings. 76 | */ 77 | lazy val openIDSettings = spy(OpenIDSettings( 78 | providerURL = "https://me.yahoo.com/", 79 | callbackURL = "http://localhost:9000/authenticate/yahoo", 80 | axRequired = Map( 81 | "fullname" -> "http://axschema.org/namePerson", 82 | "email" -> "http://axschema.org/contact/email", 83 | "image" -> "http://axschema.org/media/image/default" 84 | ), 85 | realm = Some("http://localhost:9000") 86 | )) 87 | 88 | /** 89 | * The provider to test. 90 | */ 91 | lazy val provider = new YahooProvider(httpLayer, openIDService, openIDSettings) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/SocialProviderRegistrySpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers 17 | 18 | import com.mohiva.play.silhouette.impl.providers.oauth1.TwitterProvider 19 | import com.mohiva.play.silhouette.impl.providers.oauth2.{ GoogleProvider, FacebookProvider } 20 | import com.mohiva.play.silhouette.impl.providers.openid.YahooProvider 21 | import org.specs2.mock.Mockito 22 | import org.specs2.specification.Scope 23 | import play.api.test.PlaySpecification 24 | 25 | /** 26 | * Test case for the [[com.mohiva.play.silhouette.impl.providers.SocialProviderRegistry]] class. 27 | */ 28 | class SocialProviderRegistrySpec extends PlaySpecification with Mockito { 29 | 30 | "The `get` method" should { 31 | "return a provider by its type" in new Context { 32 | registry.get[GoogleProvider] must beSome(providers(1)) 33 | } 34 | 35 | "return None if no provider for the given type exists" in new Context { 36 | registry.get[YahooProvider] must beNone 37 | } 38 | 39 | "return a provider by its ID as SocialProvider" in new Context { 40 | val provider = registry.get[SocialProvider](GoogleProvider.ID) 41 | 42 | provider must beSome.like { 43 | case value => 44 | value.id must be equalTo providers(1).id 45 | value must beAnInstanceOf[SocialProvider] 46 | } 47 | } 48 | 49 | "return a provider by its ID as OAuth2Provider" in new Context { 50 | val provider = registry.get[OAuth2Provider](GoogleProvider.ID) 51 | 52 | provider must beSome.like { 53 | case value => 54 | value.id must be equalTo providers(1).id 55 | value must beAnInstanceOf[OAuth2Provider] 56 | } 57 | } 58 | 59 | "return None if no provider for the given ID exists" in new Context { 60 | registry.get[SocialProvider](YahooProvider.ID) must beNone 61 | } 62 | } 63 | 64 | "The `getSeq` method" should { 65 | "return a list of providers by it's sub type" in new Context { 66 | val list = registry.getSeq[OAuth2Provider] 67 | list.head.id must be equalTo providers.head.id 68 | list(1).id must be equalTo providers(1).id 69 | } 70 | } 71 | 72 | /** 73 | * The context. 74 | */ 75 | trait Context extends Scope { 76 | 77 | /** 78 | * Some social providers. 79 | */ 80 | val providers = { 81 | val facebook = mock[FacebookProvider] 82 | facebook.id returns FacebookProvider.ID 83 | val google = mock[GoogleProvider] 84 | google.id returns GoogleProvider.ID 85 | val twitter = mock[TwitterProvider] 86 | twitter.id returns TwitterProvider.ID 87 | 88 | Seq( 89 | facebook, 90 | google, 91 | twitter 92 | ) 93 | } 94 | 95 | /** 96 | * The registry to test. 97 | */ 98 | val registry = SocialProviderRegistry(providers) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/Silhouette.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | import javax.inject.Inject 19 | 20 | import com.mohiva.play.silhouette.api.actions._ 21 | import play.api.mvc.AnyContent 22 | 23 | /** 24 | * The Silhouette stack. 25 | * 26 | * Inject an instance of this trait into your controller to provide all the Silhouette actions. 27 | * 28 | * @tparam E The type of the environment. 29 | */ 30 | trait Silhouette[E <: Env] { 31 | 32 | /** 33 | * The Silhouette environment. 34 | */ 35 | val env: Environment[E] 36 | 37 | /** 38 | * The secured action stack. 39 | */ 40 | val securedAction: SecuredAction 41 | 42 | /** 43 | * The unsecured action stack. 44 | */ 45 | val unsecuredAction: UnsecuredAction 46 | 47 | /** 48 | * The user aware action stack. 49 | */ 50 | val userAwareAction: UserAwareAction 51 | 52 | /** 53 | * Provides the secured action implementation. 54 | * 55 | * @return The secured action implementation. 56 | */ 57 | def SecuredAction: SecuredActionBuilder[E, AnyContent] = securedAction(env) 58 | 59 | /** 60 | * Provides the secured request handler implementation. 61 | * 62 | * @return The secured request handler implementation. 63 | */ 64 | def SecuredRequestHandler: SecuredRequestHandlerBuilder[E] = securedAction.requestHandler(env) 65 | 66 | /** 67 | * Provides the unsecured action implementation. 68 | * 69 | * @return The unsecured action implementation. 70 | */ 71 | def UnsecuredAction: UnsecuredActionBuilder[E, AnyContent] = unsecuredAction(env) 72 | 73 | /** 74 | * Provides the unsecured request handler implementation. 75 | * 76 | * @return The unsecured request handler implementation. 77 | */ 78 | def UnsecuredRequestHandler: UnsecuredRequestHandlerBuilder[E] = unsecuredAction.requestHandler(env) 79 | 80 | /** 81 | * Provides the user-aware action implementation. 82 | * 83 | * @return The user-aware action implementation. 84 | */ 85 | def UserAwareAction: UserAwareActionBuilder[E, AnyContent] = userAwareAction(env) 86 | 87 | /** 88 | * Provides the user-aware request handler implementation. 89 | * 90 | * @return The user-aware request handler implementation. 91 | */ 92 | def UserAwareRequestHandler: UserAwareRequestHandlerBuilder[E] = userAwareAction.requestHandler(env) 93 | } 94 | 95 | /** 96 | * Provides the Silhouette stack. 97 | * 98 | * @param env The Silhouette environment. 99 | * @param securedAction The secured action stack. 100 | * @param userAwareAction The user aware action stack. 101 | * @tparam E The type of the environment. 102 | */ 103 | class SilhouetteProvider[E <: Env] @Inject() ( 104 | val env: Environment[E], 105 | val securedAction: SecuredAction, 106 | val unsecuredAction: UnsecuredAction, 107 | val userAwareAction: UserAwareAction 108 | ) extends Silhouette[E] 109 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 6.0.1 2 | 3 | - Update to Play 2.7.3 4 | - Add support for Scala 2.13 5 | 6 | ## 6.0 7 | 8 | - Update to Play 2.7 9 | 10 | ## 5.0 11 | 12 | - Update to Play 2.6 13 | - Handling of OAuth2 based user state with the help of the new social state handler implementation (thanks to @Saheb) 14 | - Implement BCryptSha256PasswordHasher to avoid password truncating issue 15 | - Better error messages for OAuth2 based errors 16 | - Remove Clef support 17 | 18 | ## 4.0 (2016-07-14) 19 | 20 | - Update to Play 2.5 21 | - Removed Play Messages instance from Event, Authorization and ErrorHandler types. The I18nSupport trait should be used instead, to get the Messages instance for the current request 22 | - Rewrite Silhouette trait to provide injectable actions (this is now the default method from Play 2.5 on) 23 | - Every SecuredAction can now override the global(default injected) error handler if needed 24 | - A controller is not bound to a single Authenticator anymore 25 | - Remove SecuredErrorHandler in favour of injectable error handler 26 | - Pass the auth info to the profile parsers to easier query additional data from the provider API 27 | - Add UnsecuredRequestHandler and UnsecuredAction 28 | - Dropped Scala 2.10 support 29 | - Projects separated 30 | - silhouette-password-bcrypt -> contains BCrypt password hasher 31 | - silhouette-persistence -> contains base implementations for the persistence layer 32 | - silhouette-persistence-memory -> in-memory implementation of the persistence layer 33 | - Use request extractors to find authenticator values in other parts of the request 34 | - Fix overriding settings method for Providers (thanks @felipefzdz) 35 | - Allow to override the API URL in the OAuth1 and OAuth2 providers 36 | - Allow to override authentication provider constants 37 | - Support for Auth0 authentication provider (thanks @lucamilanesio) 38 | - Support for Gitlab authentication provider (thanks @ThmX) 39 | - Support for CAS authentication provider (thanks @SBSMMO) 40 | - Issue #435: copy customClaims when renewing JWTToken (thanks @mizerlou) 41 | - Define meaningful interface for password re-hashing (thanks @alexmojaki) 42 | - Play Framework independent crypto implementation 43 | 44 | ## 3.0 (2015-07-14) 45 | 46 | - Update to Play 2.4 47 | - Stateless and non-stateless CookieAuthenticator 48 | - Allow to customize the Gravatar service 49 | - Use scala.concurrent.duration.FiniteDuration instead of Int for duration based values 50 | - A lot of API enhancements 51 | 52 | ## 2.0 (2015-03-28) 53 | 54 | - Use lazy val to initialize SecureRandom, so that initialization occurs also async 55 | - Refactor authenticators and add BearerTokenAuthenticator, JWTAuthenticator, SessionAuthenticator and DummyAuthenticator 56 | - Better error handling for authenticators 57 | - Authenticators now using an extra backing store instead of only the cache 58 | - Split up SocialProvider.authenticate method into authenticate and retrieveProfile methods 59 | - Remove authInfo from SocialProfile 60 | - Add OAuth1 token secret implementation 61 | - Add OAuth2 state implementation 62 | - Documentation is now included in the repository and hosted on Read The Docs 63 | - Renamed packages "core" to "api", "contrib" to "impl", "utils" to "util" 64 | - Reorganized the project structure (moved all providers into the "impl" package, moved some classes/traits) 65 | - Add request handlers 66 | - Add request providers in combination with HTTP basic auth provider 67 | - Add Dropbox provider 68 | - Add Clef provider 69 | - Add request extractors 70 | - Better social profile builder implementation 71 | - Add OpenID providers Steam and Yahoo 72 | - Better error handling 73 | 74 | ## 1.0 (2014-06-12) 75 | 76 | - First release for Play 2.3 77 | 78 | ## 0.9 (2014-06-12) 79 | 80 | - First release for Play 2.2 81 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/providers/openid/services/PlayOpenIDService.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.impl.providers.openid.services 21 | 22 | import com.mohiva.play.silhouette.impl.providers.{ OpenIDInfo, OpenIDService, OpenIDSettings } 23 | import play.api.libs.openid.OpenIdClient 24 | import play.api.mvc.Request 25 | 26 | import scala.concurrent.{ ExecutionContext, Future } 27 | import scala.util.{ Failure, Success, Try } 28 | 29 | /** 30 | * The OpenID service implementation which wraps Play Framework's OpenID implementation. 31 | * 32 | * @param client The OpenID client implementation. 33 | * @param settings The OpenID settings. 34 | */ 35 | class PlayOpenIDService(val client: OpenIdClient, val settings: OpenIDSettings) extends OpenIDService { 36 | 37 | /** 38 | * The type of this class. 39 | */ 40 | override type Self = PlayOpenIDService 41 | 42 | /** 43 | * Retrieve the URL where the user should be redirected to start the OpenID authentication process. 44 | * 45 | * @param openID The OpenID to use for authentication. 46 | * @param resolvedCallbackURL The full callback URL to the application after a successful authentication. 47 | * @param ec The execution context to handle the asynchronous operations. 48 | * @return The redirect URL where the user should be redirected to start the OpenID authentication process. 49 | */ 50 | override def redirectURL(openID: String, resolvedCallbackURL: String)(implicit ec: ExecutionContext): Future[String] = { 51 | Try { 52 | client.redirectURL(openID, resolvedCallbackURL, settings.axRequired.toSeq, settings.axOptional.toSeq, settings.realm) 53 | } match { 54 | case Success(f) => f 55 | case Failure(e) => Future.failed(e) 56 | } 57 | } 58 | 59 | /** 60 | * From a request corresponding to the callback from the OpenID server, check the identity of the current user. 61 | * 62 | * @param request The current request. 63 | * @param ec The execution context to handle the asynchronous operations. 64 | * @tparam B The type of the request body. 65 | * @return A OpenIDInfo in case of success, Exception otherwise. 66 | */ 67 | override def verifiedID[B](implicit request: Request[B], ec: ExecutionContext) = Try { 68 | client.verifiedId(request).map(info => OpenIDInfo(info.id, info.attributes)) 69 | } match { 70 | case Success(f) => f 71 | case Failure(e) => Future.failed(e) 72 | } 73 | 74 | /** 75 | * Gets a service initialized with a new settings object. 76 | * 77 | * @param f A function which gets the settings passed and returns different settings. 78 | * @return An instance of the service initialized with new settings. 79 | */ 80 | override def withSettings(f: (OpenIDSettings) => OpenIDSettings) = { 81 | new PlayOpenIDService(client, f(settings)) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/impl/providers/openid/SteamProvider.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers.openid 17 | 18 | import com.mohiva.play.silhouette.api.LoginInfo 19 | import com.mohiva.play.silhouette.api.util.HTTPLayer 20 | import com.mohiva.play.silhouette.impl.providers._ 21 | import com.mohiva.play.silhouette.impl.providers.openid.SteamProvider._ 22 | 23 | import scala.concurrent.Future 24 | 25 | /** 26 | * Base Steam OpenID Provider. 27 | * 28 | * @see https://steamcommunity.com/dev 29 | */ 30 | trait BaseSteamProvider extends OpenIDProvider { 31 | 32 | /** 33 | * The content type to parse a profile from. 34 | */ 35 | override type Content = Unit 36 | 37 | /** 38 | * Gets the provider ID. 39 | * 40 | * @return The provider ID. 41 | */ 42 | override val id = ID 43 | 44 | /** 45 | * Defines the URLs that are needed to retrieve the profile data. 46 | */ 47 | override protected val urls = Map[String, String]() 48 | 49 | /** 50 | * Builds the social profile. 51 | * 52 | * @param authInfo The auth info received from the provider. 53 | * @return On success the build social profile, otherwise a failure. 54 | */ 55 | override protected def buildProfile(authInfo: OpenIDInfo): Future[Profile] = { 56 | profileParser.parse((), authInfo) 57 | } 58 | } 59 | 60 | /** 61 | * The profile parser for the common social profile. 62 | */ 63 | class SteamProfileParser extends SocialProfileParser[Unit, CommonSocialProfile, OpenIDInfo] { 64 | 65 | /** 66 | * Parses the social profile. 67 | * 68 | * @param authInfo The auth info received from the provider. 69 | * @return The social profile from given result. 70 | */ 71 | override def parse(data: Unit, authInfo: OpenIDInfo) = Future.successful { 72 | CommonSocialProfile(loginInfo = LoginInfo(ID, authInfo.id)) 73 | } 74 | } 75 | 76 | /** 77 | * The Steam OAuth2 Provider. 78 | * 79 | * @param httpLayer The HTTP layer implementation. 80 | * @param service The OpenID service implementation. 81 | * @param settings The OpenID provider settings. 82 | */ 83 | class SteamProvider( 84 | protected val httpLayer: HTTPLayer, 85 | val service: OpenIDService, 86 | val settings: OpenIDSettings) 87 | extends BaseSteamProvider with CommonSocialProfileBuilder { 88 | 89 | /** 90 | * The type of this class. 91 | */ 92 | override type Self = SteamProvider 93 | 94 | /** 95 | * The profile parser implementation. 96 | */ 97 | override val profileParser = new SteamProfileParser 98 | 99 | /** 100 | * Gets a provider initialized with a new settings object. 101 | * 102 | * @param f A function which gets the settings passed and returns different settings. 103 | * @return An instance of the provider initialized with new settings. 104 | */ 105 | override def withSettings(f: (Settings) => Settings) = { 106 | new SteamProvider(httpLayer, service.withSettings(f), f(settings)) 107 | } 108 | } 109 | 110 | /** 111 | * The companion object. 112 | */ 113 | object SteamProvider { 114 | 115 | /** 116 | * The Steam constants. 117 | */ 118 | val ID = "steam" 119 | } 120 | -------------------------------------------------------------------------------- /silhouette/test/com/mohiva/play/silhouette/impl/providers/state/UserStateItemHandlerSpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.impl.providers.state 17 | 18 | import com.mohiva.play.silhouette.impl.providers.SocialStateItem 19 | import com.mohiva.play.silhouette.impl.providers.SocialStateItem.ItemStructure 20 | import com.mohiva.play.silhouette.impl.providers.state.UserStateItemHandler._ 21 | import org.specs2.matcher.JsonMatchers 22 | import org.specs2.mock.Mockito 23 | import org.specs2.specification.Scope 24 | import play.api.libs.json.Json 25 | import play.api.test.{ FakeRequest, PlaySpecification } 26 | 27 | import scala.concurrent.ExecutionContext.Implicits.global 28 | 29 | /** 30 | * Test case for the [[UserStateItemHandler]] class. 31 | */ 32 | class UserStateItemHandlerSpec extends PlaySpecification with Mockito with JsonMatchers { 33 | 34 | "The `item` method" should { 35 | "return the user state item" in new Context { 36 | await(userStateItemHandler.item) must be equalTo userStateItem 37 | } 38 | } 39 | 40 | "The `canHandle` method" should { 41 | "return the same item if it can handle the given item" in new Context { 42 | userStateItemHandler.canHandle(userStateItem) must beSome(userStateItem) 43 | } 44 | 45 | "should return `None` if it can't handle the given item" in new Context { 46 | val nonUserState = mock[SocialStateItem].smart 47 | 48 | userStateItemHandler.canHandle(nonUserState) must beNone 49 | } 50 | } 51 | 52 | "The `canHandle` method" should { 53 | "return false if the give item is for another handler" in new Context { 54 | val nonUserItemStructure = mock[ItemStructure].smart 55 | nonUserItemStructure.id returns "non-user-item" 56 | 57 | implicit val request = FakeRequest() 58 | userStateItemHandler.canHandle(nonUserItemStructure) must beFalse 59 | } 60 | 61 | "return true if it can handle the given `ItemStructure`" in new Context { 62 | implicit val request = FakeRequest() 63 | userStateItemHandler.canHandle(userItemStructure) must beTrue 64 | } 65 | } 66 | 67 | "The `serialize` method" should { 68 | "return a serialized value of the state item" in new Context { 69 | userStateItemHandler.serialize(userStateItem).asString must be equalTo userItemStructure.asString 70 | } 71 | } 72 | 73 | "The `unserialize` method" should { 74 | "unserialize the state item" in new Context { 75 | implicit val request = FakeRequest() 76 | 77 | await(userStateItemHandler.unserialize(userItemStructure)) must be equalTo userStateItem 78 | } 79 | } 80 | 81 | /** 82 | * The context. 83 | */ 84 | trait Context extends Scope { 85 | 86 | /** 87 | * A user state item. 88 | */ 89 | val userStateItem = UserStateItem(Map("path" -> "/login")) 90 | 91 | /** 92 | * The serialized type of the user state item. 93 | */ 94 | val userItemStructure = ItemStructure(ID, Json.toJson(userStateItem)) 95 | 96 | /** 97 | * An instance of the user state item handler. 98 | */ 99 | val userStateItemHandler = new UserStateItemHandler[UserStateItem](userStateItem) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /silhouette-persistence/src/main/scala/com/mohiva/play/silhouette/persistence/daos/InMemoryAuthInfoDAO.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence.daos 17 | 18 | import com.mohiva.play.silhouette.api.{ AuthInfo, LoginInfo } 19 | 20 | import scala.collection.mutable 21 | import scala.concurrent.ExecutionContext.Implicits.global 22 | import scala.concurrent.Future 23 | import scala.reflect.ClassTag 24 | 25 | /** 26 | * An implementation of the auth info DAO which stores the data in memory. 27 | * 28 | * This is not thread-safe implementation which should only be used for testing or development purpose. 29 | * 30 | * @param classTag The class tag for the type parameter. 31 | * @tparam T The type of the auth info to store. 32 | */ 33 | class InMemoryAuthInfoDAO[T <: AuthInfo](implicit val classTag: ClassTag[T]) extends DelegableAuthInfoDAO[T] { 34 | 35 | /** 36 | * The data store for the auth info. 37 | */ 38 | var data: mutable.HashMap[LoginInfo, T] = mutable.HashMap() 39 | 40 | /** 41 | * Finds the auth info which is linked with the specified login info. 42 | * 43 | * @param loginInfo The linked login info. 44 | * @return The retrieved auth info or None if no auth info could be retrieved for the given login info. 45 | */ 46 | def find(loginInfo: LoginInfo): Future[Option[T]] = { 47 | Future.successful(data.get(loginInfo)) 48 | } 49 | 50 | /** 51 | * Adds new auth info for the given login info. 52 | * 53 | * @param loginInfo The login info for which the auth info should be added. 54 | * @param authInfo The auth info to add. 55 | * @return The added auth info. 56 | */ 57 | def add(loginInfo: LoginInfo, authInfo: T): Future[T] = { 58 | data += (loginInfo -> authInfo) 59 | Future.successful(authInfo) 60 | } 61 | 62 | /** 63 | * Updates the auth info for the given login info. 64 | * 65 | * @param loginInfo The login info for which the auth info should be updated. 66 | * @param authInfo The auth info to update. 67 | * @return The updated auth info. 68 | */ 69 | def update(loginInfo: LoginInfo, authInfo: T): Future[T] = { 70 | data += (loginInfo -> authInfo) 71 | Future.successful(authInfo) 72 | } 73 | 74 | /** 75 | * Saves the auth info for the given login info. 76 | * 77 | * This method either adds the auth info if it doesn't exists or it updates the auth info 78 | * if it already exists. 79 | * 80 | * @param loginInfo The login info for which the auth info should be saved. 81 | * @param authInfo The auth info to save. 82 | * @return The saved auth info. 83 | */ 84 | def save(loginInfo: LoginInfo, authInfo: T): Future[T] = { 85 | find(loginInfo).flatMap { 86 | case Some(_) => update(loginInfo, authInfo) 87 | case None => add(loginInfo, authInfo) 88 | } 89 | } 90 | 91 | /** 92 | * Removes the auth info for the given login info. 93 | * 94 | * @param loginInfo The login info for which the auth info should be removed. 95 | * @return A future to wait for the process to be completed. 96 | */ 97 | def remove(loginInfo: LoginInfo): Future[Unit] = { 98 | data -= loginInfo 99 | Future.successful(()) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /silhouette/app/com/mohiva/play/silhouette/api/Environment.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.api 17 | 18 | import com.mohiva.play.silhouette.api.services.{ AuthenticatorService, IdentityService } 19 | import com.mohiva.play.silhouette.api.util.ExecutionContextProvider 20 | 21 | import scala.concurrent.ExecutionContext 22 | 23 | /** 24 | * The environment type. 25 | * 26 | * Defines the [[Identity]] and [[Authenticator]] types for an environment. It is possible 27 | * to implement as many types as needed. This has the advantage that an application isn't 28 | * bound only to a single `Identity` -> `Authenticator` combination. 29 | * 30 | * To define a new environment type create a new trait with the appropriate [[Identity]] and 31 | * [[Authenticator]] types: 32 | * 33 | * {{{ 34 | * trait SessionEnv extends Env { 35 | * type I = User 36 | * type A = SessionAuthenticator 37 | * } 38 | * trait JWTEnv extends Env { 39 | * type I = User 40 | * type A = JWTAuthenticator 41 | * } 42 | * }}} 43 | */ 44 | trait Env { 45 | type I <: Identity 46 | type A <: Authenticator 47 | } 48 | 49 | /** 50 | * Provides the components needed to handle a secured request. 51 | * 52 | * It's possible to declare different environments for different environment types. The 53 | * [[com.mohiva.play.silhouette.api.services.IdentityService]] and the 54 | * [[com.mohiva.play.silhouette.api.services.AuthenticatorService]] are bound to the appropriate types 55 | * defined in the environment type. But the [[EventBus]] and the list of [[RequestProvider]] 56 | * instances can be defined as needed for every environment type. 57 | */ 58 | trait Environment[E <: Env] extends ExecutionContextProvider { 59 | 60 | /** 61 | * Gets the identity service implementation. 62 | * 63 | * @return The identity service implementation. 64 | */ 65 | def identityService: IdentityService[E#I] 66 | 67 | /** 68 | * Gets the authenticator service implementation. 69 | * 70 | * @return The authenticator service implementation. 71 | */ 72 | def authenticatorService: AuthenticatorService[E#A] 73 | 74 | /** 75 | * Gets the list of request providers. 76 | * 77 | * @return The list of request providers. 78 | */ 79 | def requestProviders: Seq[RequestProvider] 80 | 81 | /** 82 | * The event bus implementation. 83 | * 84 | * @return The event bus implementation. 85 | */ 86 | def eventBus: EventBus 87 | } 88 | 89 | /** 90 | * Companion object to easily create environment instances. 91 | * 92 | * {{{ 93 | * Environment[SessionEnv](...) 94 | * Environment[JWTEnv](...) 95 | * }}} 96 | */ 97 | object Environment { 98 | def apply[E <: Env]( 99 | identityServiceImpl: IdentityService[E#I], 100 | authenticatorServiceImpl: AuthenticatorService[E#A], 101 | requestProvidersImpl: Seq[RequestProvider], 102 | eventBusImpl: EventBus)(implicit ec: ExecutionContext) = new Environment[E] { 103 | val identityService = identityServiceImpl 104 | val authenticatorService = authenticatorServiceImpl 105 | val requestProviders = requestProvidersImpl 106 | val eventBus = eventBusImpl 107 | val executionContext = ec 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /silhouette-persistence/src/test/scala/com/mohiva/play/silhouette/persistence/repositories/CacheAuthenticatorRepositorySpec.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Mohiva Organisation (license at mohiva dot com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.mohiva.play.silhouette.persistence.repositories 17 | 18 | import com.mohiva.play.silhouette.api.StorableAuthenticator 19 | import com.mohiva.play.silhouette.api.util.CacheLayer 20 | import com.mohiva.play.silhouette.test.WaitPatience 21 | import org.specs2.concurrent.ExecutionEnv 22 | import org.specs2.mock.Mockito 23 | import org.specs2.mutable.Specification 24 | import org.specs2.specification.Scope 25 | 26 | import scala.concurrent.Future 27 | import scala.concurrent.duration.Duration 28 | 29 | /** 30 | * Test case for the [[CacheAuthenticatorRepository]] class. 31 | */ 32 | class CacheAuthenticatorRepositorySpec(implicit ev: ExecutionEnv) extends Specification with Mockito with WaitPatience { 33 | 34 | "The `find` method" should { 35 | "return value from cache" in new Context { 36 | cacheLayer.find[StorableAuthenticator]("test-id") returns Future.successful(Some(authenticator)) 37 | 38 | repository.find("test-id") must beSome(authenticator).awaitWithPatience 39 | there was one(cacheLayer).find[StorableAuthenticator]("test-id") 40 | } 41 | 42 | "return None if value couldn't be found in cache" in new Context { 43 | cacheLayer.find[StorableAuthenticator]("test-id") returns Future.successful(None) 44 | 45 | repository.find("test-id") must beNone.awaitWithPatience 46 | there was one(cacheLayer).find[StorableAuthenticator]("test-id") 47 | } 48 | } 49 | 50 | "The `add` method" should { 51 | "add value in cache" in new Context { 52 | authenticator.id returns "test-id" 53 | cacheLayer.save("test-id", authenticator, Duration.Inf) returns Future.successful(authenticator) 54 | 55 | repository.add(authenticator) must beEqualTo(authenticator).awaitWithPatience 56 | there was one(cacheLayer).save("test-id", authenticator, Duration.Inf) 57 | } 58 | } 59 | 60 | "The `update` method" should { 61 | "update value in cache" in new Context { 62 | authenticator.id returns "test-id" 63 | cacheLayer.save("test-id", authenticator, Duration.Inf) returns Future.successful(authenticator) 64 | 65 | repository.update(authenticator) must beEqualTo(authenticator).awaitWithPatience 66 | there was one(cacheLayer).save("test-id", authenticator, Duration.Inf) 67 | } 68 | } 69 | 70 | "The `remove` method" should { 71 | "remove value from cache" in new Context { 72 | cacheLayer.remove("test-id") returns Future.successful(()) 73 | 74 | repository.remove("test-id") must beEqualTo(()).awaitWithPatience 75 | there was one(cacheLayer).remove("test-id") 76 | } 77 | } 78 | 79 | /** 80 | * The context. 81 | */ 82 | trait Context extends Scope { 83 | 84 | /** 85 | * A storable authenticator. 86 | */ 87 | lazy val authenticator = mock[StorableAuthenticator] 88 | 89 | /** 90 | * The cache layer implementation. 91 | */ 92 | lazy val cacheLayer = mock[CacheLayer] 93 | 94 | /** 95 | * The repository to test. 96 | */ 97 | lazy val repository = new CacheAuthenticatorRepository[StorableAuthenticator](cacheLayer) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /silhouette-password-bcrypt/src/main/scala/com/mohiva/play/silhouette/password/BCryptPasswordHasher.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work: SecureSocial (https://github.com/jaliss/securesocial) 3 | * Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss 4 | * 5 | * Derivative work: Silhouette (https://github.com/mohiva/play-silhouette) 6 | * Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com) 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package com.mohiva.play.silhouette.password 21 | 22 | import com.mohiva.play.silhouette.api.util.{ PasswordHasher, PasswordInfo } 23 | import com.mohiva.play.silhouette.password.BCryptPasswordHasher._ 24 | import org.mindrot.jbcrypt.BCrypt 25 | 26 | /** 27 | * Implementation of the password hasher based on BCrypt. 28 | * 29 | * @param logRounds The log2 of the number of rounds of hashing to apply. 30 | * @see [[http://www.mindrot.org/files/jBCrypt/jBCrypt-0.2-doc/BCrypt.html#gensalt(int) gensalt]] 31 | */ 32 | class BCryptPasswordHasher(logRounds: Int = 10) extends PasswordHasher { 33 | 34 | /** 35 | * Gets the ID of the hasher. 36 | * 37 | * @return The ID of the hasher. 38 | */ 39 | override def id = ID 40 | 41 | /** 42 | * Hashes a password. 43 | * 44 | * This implementation does not return the salt separately because it is embedded in the hashed password. 45 | * Other implementations might need to return it so it gets saved in the backing store. 46 | * 47 | * @param plainPassword The password to hash. 48 | * @return A PasswordInfo containing the hashed password. 49 | */ 50 | override def hash(plainPassword: String) = PasswordInfo( 51 | hasher = id, 52 | password = BCrypt.hashpw(plainPassword, BCrypt.gensalt(logRounds)) 53 | ) 54 | 55 | /** 56 | * Checks if a password matches the hashed version. 57 | * 58 | * @param passwordInfo The password retrieved from the backing store. 59 | * @param suppliedPassword The password supplied by the user trying to log in. 60 | * @return True if the password matches, false otherwise. 61 | */ 62 | override def matches(passwordInfo: PasswordInfo, suppliedPassword: String) = { 63 | BCrypt.checkpw(suppliedPassword, passwordInfo.password) 64 | } 65 | 66 | /** 67 | * Indicates if a password info hashed with this hasher is deprecated. 68 | * 69 | * In case of the BCrypt password hasher, a password is deprecated if the log rounds have changed. 70 | * 71 | * @param passwordInfo The password info to check the deprecation status for. 72 | * @return True if the given password info is deprecated, false otherwise. If a hasher isn't 73 | * suitable for the given password, this method should return None. 74 | */ 75 | override def isDeprecated(passwordInfo: PasswordInfo): Option[Boolean] = { 76 | Option(isSuitable(passwordInfo)).collect { 77 | case true => 78 | val LogRoundsPattern(lr) = passwordInfo.password 79 | // Is deprecated if the log rounds has changed 80 | lr != logRounds.toString 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * The companion object. 87 | */ 88 | object BCryptPasswordHasher { 89 | 90 | /** 91 | * The ID of the hasher. 92 | */ 93 | val ID = "bcrypt" 94 | 95 | /** 96 | * The pattern to extract the log rounds from the password string. 97 | */ 98 | val LogRoundsPattern = """^\$\w{2}\$(\d{1,2})\$.+""".r 99 | } 100 | --------------------------------------------------------------------------------