Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
155 lines (136 sloc) 5.01 KB
/**
* Original work: SecureSocial (https://github.com/jaliss/securesocial)
* Copyright 2013 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss
*
* Derivative work: Silhouette (https://github.com/mohiva/play-silhouette)
* Modifications Copyright 2015 Mohiva Organisation (license at mohiva dot com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mohiva.play.silhouette.impl.providers.oauth2
import com.mohiva.play.silhouette.api.LoginInfo
import com.mohiva.play.silhouette.api.util.HTTPLayer
import com.mohiva.play.silhouette.impl.exceptions.ProfileRetrievalException
import com.mohiva.play.silhouette.impl.providers._
import com.mohiva.play.silhouette.impl.providers.oauth2.FacebookProvider._
import play.api.libs.json.{ JsObject, JsValue }
import scala.concurrent.Future
/**
* Base Facebook OAuth2 Provider.
*
* @see https://developers.facebook.com/tools/explorer
* @see https://developers.facebook.com/docs/graph-api/reference/user
* @see https://developers.facebook.com/docs/facebook-login/access-tokens
*/
trait BaseFacebookProvider extends OAuth2Provider {
/**
* The content type to parse a profile from.
*/
override type Content = JsValue
/**
* The provider ID.
*/
override val id = ID
/**
* Defines the URLs that are needed to retrieve the profile data.
*/
override protected val urls = Map("api" -> settings.apiURL.getOrElse(API))
/**
* Builds the social profile.
*
* @param authInfo The auth info received from the provider.
* @return On success the build social profile, otherwise a failure.
*/
override protected def buildProfile(authInfo: OAuth2Info): Future[Profile] = {
httpLayer.url(urls("api").format(authInfo.accessToken)).get().flatMap { response =>
val json = response.json
(json \ "error").asOpt[JsObject] match {
case Some(error) =>
val errorMsg = (error \ "message").as[String]
val errorType = (error \ "type").as[String]
val errorCode = (error \ "code").as[Int]
throw new ProfileRetrievalException(SpecifiedProfileError.format(id, errorMsg, errorType, errorCode))
case _ => profileParser.parse(json, authInfo)
}
}
}
}
/**
* The profile parser for the common social profile.
*/
class FacebookProfileParser extends SocialProfileParser[JsValue, CommonSocialProfile, OAuth2Info] {
/**
* Parses the social profile.
*
* @param json The content returned from the provider.
* @param authInfo The auth info to query the provider again for additional data.
* @return The social profile from given result.
*/
override def parse(json: JsValue, authInfo: OAuth2Info) = Future.successful {
val userID = (json \ "id").as[String]
val firstName = (json \ "first_name").asOpt[String]
val lastName = (json \ "last_name").asOpt[String]
val fullName = (json \ "name").asOpt[String]
val avatarURL = (json \ "picture" \ "data" \ "url").asOpt[String]
val email = (json \ "email").asOpt[String]
CommonSocialProfile(
loginInfo = LoginInfo(ID, userID),
firstName = firstName,
lastName = lastName,
fullName = fullName,
avatarURL = avatarURL,
email = email)
}
}
/**
* The Facebook OAuth2 Provider.
*
* @param httpLayer The HTTP layer implementation.
* @param stateHandler The state provider implementation.
* @param settings The provider settings.
*/
class FacebookProvider(
protected val httpLayer: HTTPLayer,
protected val stateHandler: SocialStateHandler,
val settings: OAuth2Settings)
extends BaseFacebookProvider with CommonSocialProfileBuilder {
/**
* The type of this class.
*/
override type Self = FacebookProvider
/**
* The profile parser implementation.
*/
override val profileParser = new FacebookProfileParser
/**
* Gets a provider initialized with a new settings object.
*
* @param f A function which gets the settings passed and returns different settings.
* @return An instance of the provider initialized with new settings.
*/
override def withSettings(f: (Settings) => Settings) = new FacebookProvider(httpLayer, stateHandler, f(settings))
}
/**
* The companion object.
*/
object FacebookProvider {
/**
* The error messages.
*/
val SpecifiedProfileError = "[Silhouette][%s] Error retrieving profile information. Error message: %s, type: %s, code: %s"
/**
* The Facebook constants.
*/
val ID = "facebook"
val API = "https://graph.facebook.com/v2.3/me?fields=name,first_name,last_name,picture,email&return_ssl_resources=1&access_token=%s"
}
You can’t perform that action at this time.