Question

Using Play! 2.0.4 and SecureSocial 2 (http://securesocial.ws/). Scala implementation. Most of this question will be directly referencing the sample here: https://github.com/jaliss/securesocial/blob/2.0.12/samples/scala/demo/app/service/InMemoryUserService.scala

I'm trying to figure out the author's original intention as to backend interaction with a storage service. With respect to the def find(id: UserId) and the def findByEmailAndProvider(email: String, providerId: String): methods, is SecureSocial expecting to give either a Facebook ID or email that can be used to return a full SocialUser class?

If that's the case, then how do we assign our own IDs to each user so that we can link accounts together? Because it seems that if I extend Identity to include a universal ID then would that also require rewriting/extending the social providers, too?

At minimum, I'm trying to figure out what API/parameters I should expose for the find and save methods in a backend service. Let me know if this question needs to be clarified :)

Was it helpful?

Solution

After having a couple days to make some design considerations and better understand SecureSocial, I realized that implementing the find and save methods were not that difficult to understand. It's properly designing the logic in a backend service that matters.

Basically, I created a PlatformUser class that extends the Identity class and includes User ID and profile data pulled from a backend class. Here's how it looks:

case class PlatformUser(
  guid: String,
  suspended: Boolean,
  id: UserId, 
  firstName: String, 
  lastName: String, 
  fullName: String, 
  email: Option[String],
  avatarUrl: Option[String], 
  authMethod: AuthenticationMethod,
  oAuth1Info: Option[OAuth1Info] = None,
  oAuth2Info: Option[OAuth2Info] = None,
  passwordInfo: Option[PasswordInfo] = None,
  communityProfile: Option[String] = None

) extends Identity

My object PlatformUser contains code that accesses a backend HTTP API to transfer data back and forth. Here's how I implement the find and save methods:

  def find(id: UserId): Option[PlatformUser] = {
    PlatformUser.fetch(id)
  }

  def findByEmailAndProvider(email: String, providerId: String): Option[PlatformUser] = {
    PlatformUser.fetch(email, providerId)
  }

  def save(user: Identity): PlatformUser = {
    PlatformUser.store(user)
  }

The logic for merging accounts remains in the backend service as well. Now if the user doesn't already exist, the backend service generates a platform ID. If an email of an incoming Identity is found to already exist on the platform, then an auto-link of identities is performed to the existing platform ID (unless its found that the email is being used on multiple accounts for the same social network, where an error will be triggered). The user is notified by email to their primary address of the auto-link.

The last thing left is populating the communityProfile. If the backend service doesn't find one, then that field returns as None. I then automatically redirect the user to a "registration" page where they need to complete their profile.

That's about it. I hope this helps future devs who are trying to figure out more complicated uses of SecureSocial.

OTHER TIPS

"If an email of an incoming Identity is found to already exist on the platform, then an auto-link of identities is performed to the existing platform ID". I am assuming when you say auto-link, this would be during sign on. If so, this would be a security flaw.

A malicious user could set his twitter email to your mail id. When he logs in using twitter, it gets "auto-linked" to your account!

See this thread for further analysis https://github.com/jaliss/securesocial/issues/14

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top