Skip to content
This repository has been archived by the owner on Sep 12, 2021. It is now read-only.

Refactor social auth providers #121

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Silhouette Seed Template
=====================================

The Silhouette Seed project is an Activator template which shows how [Silhouette](https://github.com/mohiva/play-silhouette) can be implemented in a Play Framework application. It's a starting point which can be extended to fit your needs.
The Silhouette Seed project is an example application which shows how [Silhouette](https://github.com/mohiva/play-silhouette) can be implemented in a Play Framework application. It's a starting point which can be extended to fit your needs.

## Example

Expand All @@ -23,16 +23,32 @@ Or you can find a running example of this template under the following URL: http
* Password reset/change functionality
* Account activation functionality
* Email sending and auth token cleanup
* [Security headers](https://www.playframework.com/documentation/2.4.x/SecurityHeaders)
* [CSRF Protection](https://www.playframework.com/documentation/2.4.x/ScalaCsrf)
* [Security headers](https://www.playframework.com/documentation/latest/SecurityHeaders)
* [CSRF Protection](https://www.playframework.com/documentation/latest/ScalaCsrf)

## Documentation

Consult the [Silhouette documentation](http://silhouette.mohiva.com/docs) for more information. If you need help with the integration of Silhouette into your project, don't hesitate and ask questions in our [mailing list](https://groups.google.com/forum/#!forum/play-silhouette) or on [Stack Overflow](http://stackoverflow.com/questions/tagged/playframework).

## Activator
## Social Authentication Providers

See https://typesafe.com/activator/template/play-silhouette-seed
If you are testing social authentication, you'll want to set up a Heroku test application as it's publicly available and free for developers. Play integration is [straightforward](https://devcenter.heroku.com/articles/play-support).

### Twitter

Create an application in [Twitter Developer Console](https://developer.twitter.com/en/apps).

The key and secret that you should use for authentication is under "Keys and Tokens" tab in the "Consumer API keys" section.

### Github

Create an application in [Github Developer Console](https://github.com/settings/applications/new).

### Google

You will need to [set up an application](https://developers.google.com/identity/protocols/OpenIDConnect#appsetup) in Google API Console and enable the People API, then [set up authentication](https://developers.google.com/identity/protocols/OpenIDConnect#authenticatingtheuser).

There is a good guide at [oauth.com](https://www.oauth.com/oauth2-servers/signing-in-with-google/create-an-application/).

# License

Expand Down
38 changes: 12 additions & 26 deletions app/modules/SilhouetteModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,16 @@ class SilhouetteModule extends AbstractModule with ScalaModule {
def provideSocialProviderRegistry(
facebookProvider: FacebookProvider,
googleProvider: GoogleProvider,
vkProvider: VKProvider,
githubProvider: GitHubProvider,
twitterProvider: TwitterProvider,
vkProvider: VKProvider,
xingProvider: XingProvider,
yahooProvider: YahooProvider): SocialProviderRegistry = {

SocialProviderRegistry(Seq(
googleProvider,
facebookProvider,
googleProvider,
githubProvider,
twitterProvider,
vkProvider,
xingProvider,
Expand Down Expand Up @@ -229,12 +231,7 @@ class SilhouetteModule extends AbstractModule with ScalaModule {
/**
* Provides the auth info repository.
*
* @param totpInfoDAO The implementation of the delegable totp auth info DAO.
* @param passwordInfoDAO The implementation of the delegable password auth info DAO.
* @param oauth1InfoDAO The implementation of the delegable OAuth1 auth info DAO.
* @param oauth2InfoDAO The implementation of the delegable OAuth2 auth info DAO.
* @param openIDInfoDAO The implementation of the delegable OpenID auth info DAO.
* @return The auth info repository instance.
* XXX This should be done the same way as HTTP filters.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the theory here is that you should be able to define these from configuration, and have them loaded in by dependency injection automatically: see https://github.com/playframework/playframework/blob/master/core/play/src/main/scala/play/api/http/HttpFilters.scala#L78 for an implementation.

*/
@Provides
def provideAuthInfoRepository(
Expand All @@ -243,7 +240,6 @@ class SilhouetteModule extends AbstractModule with ScalaModule {
oauth1InfoDAO: DelegableAuthInfoDAO[OAuth1Info],
oauth2InfoDAO: DelegableAuthInfoDAO[OAuth2Info],
openIDInfoDAO: DelegableAuthInfoDAO[OpenIDInfo]): AuthInfoRepository = {

new DelegableAuthInfoRepository(totpInfoDAO, passwordInfoDAO, oauth1InfoDAO, oauth2InfoDAO, openIDInfoDAO)
}

Expand Down Expand Up @@ -370,23 +366,6 @@ class SilhouetteModule extends AbstractModule with ScalaModule {
new GoogleTotpProvider(passwordHasherRegistry)
}

/**
* Provides the Facebook provider.
*
* @param httpLayer The HTTP layer implementation.
* @param socialStateHandler The social state handler implementation.
* @param configuration The Play configuration.
* @return The Facebook provider.
*/
@Provides
def provideFacebookProvider(
httpLayer: HTTPLayer,
socialStateHandler: SocialStateHandler,
configuration: Configuration): FacebookProvider = {

new FacebookProvider(httpLayer, socialStateHandler, configuration.underlying.as[OAuth2Settings]("silhouette.facebook"))
}

/**
* Provides the Google provider.
*
Expand All @@ -404,6 +383,13 @@ class SilhouetteModule extends AbstractModule with ScalaModule {
new GoogleProvider(httpLayer, socialStateHandler, configuration.underlying.as[OAuth2Settings]("silhouette.google"))
}

@Provides
def provideGitHubProvider(httpLayer: HTTPLayer,
socialStateHandler: SocialStateHandler,
configuration: Configuration): GitHubProvider = {
new GitHubProvider(httpLayer, socialStateHandler, configuration.underlying.as[OAuth2Settings]("silhouette.github"))
}

/**
* Provides the VK provider.
*
Expand Down
42 changes: 16 additions & 26 deletions conf/application.prod.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include "application.conf"
include "application"

# Use the "playGenerateSecret" sbt task to generate keys here.
play.http.secret.key=${?PLAY_APP_SECRET}

# Allow all proxies for Heroku so that X-Forwarded headers can be read by Play
Expand All @@ -19,37 +20,26 @@ play.mailer {
}

silhouette {
callback.host = "tersesystems-silhouette-seed.herokuapp.com"
callback.scheme = "https"

cookie.secure = true

# Authenticator settings
authenticator.cookieDomain="play-silhouette-seed.herokuapp.com"
authenticator.secureCookie=true
authenticator.cookieDomain=${silhouette.callback.host}

# OAuth1 token secret provider settings
oauth1TokenSecretProvider.cookieDomain="play-silhouette-seed.herokuapp.com"
oauth1TokenSecretProvider.secureCookie=true
oauth1TokenSecretProvider.cookieDomain=${silhouette.callback.host}

# OAuth2 state provider settings
oauth2StateProvider.cookieDomain="play-silhouette-seed.herokuapp.com"
oauth2StateProvider.secureCookie=true

# Facebook provider
facebook.redirectURL="https://play-silhouette-seed.herokuapp.com/authenticate/facebook"

# Google provider
google.redirectURL="https://play-silhouette-seed.herokuapp.com/authenticate/google"

# VK provider
vk.redirectURL="https://play-silhouette-seed.herokuapp.com/authenticate/vk"

# Twitter provider
twitter.callbackURL="https://play-silhouette-seed.herokuapp.com/authenticate/twitter"

# Xing provider
xing.callbackURL="https://play-silhouette-seed.herokuapp.com/authenticate/xing"

# Yahoo provider
yahoo.callbackURL="https://play-silhouette-seed.herokuapp.com/authenticate/yahoo"
yahoo.realm="https://play-silhouette-seed.herokuapp.com"
oauth2StateProvider.cookieDomain=${silhouette.callback.host}

# Use the "playGenerateSecret" sbt task to generate keys here.
# DO NOT REUSE THE SAME KEY, THIS IS CRYPTOGRAPHICALLY INSECURE.
oauth1TokenSecretProvider.signer.key = ${OAUTH1_SIGNER_KEY}
oauth1TokenSecretProvider.crypter.key = ${OAUTH1_CRYPTER_KEY}
socialStateHandler.signer.key = ${SOCIAL_SIGNER_KEY}
csrfStateItemHandler.signer.key = ${CSRF_SIGNER_KEY}
}

play.filters.hosts {
Expand Down
144 changes: 57 additions & 87 deletions conf/silhouette.conf
Original file line number Diff line number Diff line change
@@ -1,103 +1,73 @@
silhouette {
callback.host = "localhost:9000"
callback.host=${?SILHOUETTE_CALLBACK_HOST}

callback.scheme = "http"
callback.scheme=${?SILHOUETTE_CALLBACK_SCHEME}
callback.url = ${silhouette.callback.scheme}"://"${silhouette.callback.host}

// Disabled for testing on localhost without SSL, otherwise cookie couldn't be set
cookie.secure = false
cookie.path = "/"

# Authenticator settings
authenticator.cookieName="authenticator"
authenticator.cookiePath="/"
authenticator.secureCookie=false // Disabled for testing on localhost without SSL, otherwise cookie couldn't be set
authenticator.httpOnlyCookie=true
authenticator.sameSite="Lax"
authenticator.useFingerprinting=true
authenticator.authenticatorIdleTimeout=30 minutes
authenticator.authenticatorExpiry=12 hours
authenticator {
cookieName="authenticator"
cookiePath=${silhouette.cookie.path}
secureCookie=${silhouette.cookie.secure}
httpOnlyCookie=true
sameSite="Lax"
useFingerprinting=true
authenticatorIdleTimeout=30 minutes
authenticatorExpiry=12 hours

authenticator.rememberMe.cookieMaxAge=30 days
authenticator.rememberMe.authenticatorIdleTimeout=5 days
authenticator.rememberMe.authenticatorExpiry=30 days
rememberMe.cookieMaxAge=30 days
rememberMe.authenticatorIdleTimeout=5 days
rememberMe.authenticatorExpiry=30 days

authenticator.signer.key = "[changeme]" // A unique encryption key
authenticator.crypter.key = "[changeme]" // A unique encryption key
signer.key = "[changeme]" // A unique encryption key
signer.key = ${?AUTH_SIGNER_KEY}

crypter.key = "[changeme]" // A unique encryption key
crypter.key = ${?AUTH_CRYPTER_KEY}
}

# OAuth1 token secret provider settings
oauth1TokenSecretProvider.cookieName="OAuth1TokenSecret"
oauth1TokenSecretProvider.cookiePath="/"
oauth1TokenSecretProvider.secureCookie=false // Disabled for testing on localhost without SSL, otherwise cookie couldn't be set
oauth1TokenSecretProvider.httpOnlyCookie=true
oauth1TokenSecretProvider.sameSite="Lax"
oauth1TokenSecretProvider.expirationTime=5 minutes
oauth1TokenSecretProvider {
cookieName="OAuth1TokenSecret"
cookiePath=${silhouette.cookie.path}
secureCookie=${silhouette.cookie.secure}
httpOnlyCookie=true
sameSite="Lax"
expirationTime=5 minutes

oauth1TokenSecretProvider.signer.key = "[changeme]" // A unique encryption key
oauth1TokenSecretProvider.crypter.key = "[changeme]" // A unique encryption key
signer.key = "[changeme]" // A unique encryption key
crypter.key = "[changeme]" // A unique encryption key
}

# # OAuth2 state provider settings
oauth2StateProvider.secureCookie=${silhouette.cookie.secure}

# Social state handler
socialStateHandler.signer.key = "[changeme]" // A unique encryption key

# CSRF state item handler settings
csrfStateItemHandler.cookieName="OAuth2State"
csrfStateItemHandler.cookiePath="/"
csrfStateItemHandler.secureCookie=false // Disabled for testing on localhost without SSL, otherwise cookie couldn't be set
csrfStateItemHandler.httpOnlyCookie=true
csrfStateItemHandler.sameSite="Lax"
csrfStateItemHandler.expirationTime=5 minutes

csrfStateItemHandler.signer.key = "[changeme]" // A unique encryption key
csrfStateItemHandler {
cookieName="OAuth2State"
cookiePath=${silhouette.cookie.path}
secureCookie=${silhouette.cookie.secure}
httpOnlyCookie=true
sameSite="Lax"
expirationTime=5 minutes

# Facebook provider
facebook.authorizationURL="https://graph.facebook.com/v2.3/oauth/authorize"
facebook.accessTokenURL="https://graph.facebook.com/v2.3/oauth/access_token"
facebook.redirectURL="http://localhost:9000/authenticate/facebook"
facebook.clientID=""
facebook.clientID=${?FACEBOOK_CLIENT_ID}
facebook.clientSecret=""
facebook.clientSecret=${?FACEBOOK_CLIENT_SECRET}
facebook.scope="email"

# Google provider
google.authorizationURL="https://accounts.google.com/o/oauth2/auth"
google.accessTokenURL="https://accounts.google.com/o/oauth2/token"
google.redirectURL="http://localhost:9000/authenticate/google"
google.clientID=""
google.clientID=${?GOOGLE_CLIENT_ID}
google.clientSecret=""
google.clientSecret=${?GOOGLE_CLIENT_SECRET}
google.scope="profile email"

# VK provider
vk.authorizationURL="http://oauth.vk.com/authorize"
vk.accessTokenURL="https://oauth.vk.com/access_token"
vk.redirectURL="http://localhost:9000/authenticate/vk"
vk.clientID=""
vk.clientID=${?VK_CLIENT_ID}
vk.clientSecret=""
vk.clientSecret=${?VK_CLIENT_SECRET}
vk.scope="email"

# Twitter provider
twitter.requestTokenURL="https://twitter.com/oauth/request_token"
twitter.accessTokenURL="https://twitter.com/oauth/access_token"
twitter.authorizationURL="https://twitter.com/oauth/authenticate"
twitter.callbackURL="http://localhost:9000/authenticate/twitter"
twitter.consumerKey=""
twitter.consumerKey=${?TWITTER_CONSUMER_KEY}
twitter.consumerSecret=""
twitter.consumerSecret=${?TWITTER_CONSUMER_SECRET}

# Xing provider
xing.requestTokenURL="https://api.xing.com/v1/request_token"
xing.accessTokenURL="https://api.xing.com/v1/access_token"
xing.authorizationURL="https://api.xing.com/v1/authorize"
xing.callbackURL="http://localhost:9000/authenticate/xing"
xing.consumerKey=""
xing.consumerKey=${?XING_CONSUMER_KEY}
xing.consumerSecret=""
xing.consumerSecret=${?XING_CONSUMER_SECRET}

# Yahoo provider
yahoo.providerURL="https://me.yahoo.com/"
yahoo.callbackURL="http://localhost:9000/authenticate/yahoo"
yahoo.axRequired={
"fullname": "http://axschema.org/namePerson",
"email": "http://axschema.org/contact/email",
"image": "http://axschema.org/media/image/default"
signer.key = "[changeme]" // A unique encryption key
}
yahoo.realm="http://localhost:9000"
}

include "social/facebook"
include "social/github"
include "social/google"
include "social/twitter"
include "social/vk"
include "social/xing"
include "social/yahoo"
12 changes: 12 additions & 0 deletions conf/social/facebook.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
silhouette {
facebook {
authorizationURL="https://graph.facebook.com/v2.3/oauth/authorize"
accessTokenURL="https://graph.facebook.com/v2.3/oauth/access_token"
redirectURL=${silhouette.callback.url}"/authenticate/facebook"
clientID=""
clientID=${?FACEBOOK_CLIENT_ID}
clientSecret=""
clientSecret=${?FACEBOOK_CLIENT_SECRET}
scope="email"
}
}
12 changes: 12 additions & 0 deletions conf/social/github.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
silhouette {
github {
authorizationURL="https://github.com/login/oauth/authorize"
accessTokenURL="https://github.com/login/oauth/access_token"
redirectURL=${silhouette.callback.url}"/authenticate/github"
clientID=""
clientID=${?GITHUB_CLIENT_ID}
clientSecret=""
clientSecret=${?GITHUB_CLIENT_SECRET}
scope="profile email"
}
}
13 changes: 13 additions & 0 deletions conf/social/google.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
silhouette {
google {
authorizationURL="https://accounts.google.com/o/oauth2/auth"
accessTokenURL="https://accounts.google.com/o/oauth2/token"
redirectURL=${silhouette.callback.url}"/authenticate/google"
clientID=""
clientID=${?GOOGLE_CLIENT_ID}
clientSecret=""
clientSecret=${?GOOGLE_CLIENT_SECRET}
scope="profile email openid"
}

}
Loading