Giter Club home page Giter Club logo

Comments (43)

jaliss avatar jaliss commented on July 3, 2024

You are right. This is not something that SecureSocial provides now.

from securesocial.

poornerd avatar poornerd commented on July 3, 2024

I would also like to do this... @francisdb did you come up with a solution?

Or @jaliss do you have any ideas or tips?

from securesocial.

francisdb avatar francisdb commented on July 3, 2024

I'm still early in development of our service and as it is a side project I have not looked at this yet.

from securesocial.

poornerd avatar poornerd commented on July 3, 2024

me too... ;-) just thought I would check before trying a few more ideas

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

We need to think well how this should be done. Not everybody will need to connect multiple accounts to a single account.

from securesocial.

francisdb avatar francisdb commented on July 3, 2024

Maybe some page where you can see your linked accounts and where you can add more by clicking on the icons? A user might also want to disconnect a social account.

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

This is in the roadmap for version 2.

from securesocial.

gguan avatar gguan commented on July 3, 2024

Can we do something similar to play-authenticate? Like add merge and link methods in UserService trait?
The link/merge account feature is very useful.

from securesocial.

phammer avatar phammer commented on July 3, 2024

feature request +1.
Rename SocialUser to SocialAccount and use a user object to combine several SocialAccounts?

@jaliss: I would contribute for this feature request (implementation, testing, whatever helps you the most). I'll have a closer look at this over the weekend.

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

@gguan @phammer I have this on the road map, in fact I was going to start working on it soon. There's been a lot of chances in the code lately ;-)

I'll think what's the best way to implement this and we can share ideas @phammer.

from securesocial.

phammer avatar phammer commented on July 3, 2024

Glad to hear that and happy to give some input. Let me know when you have the master plan ready :)

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

thanks! I will :)

from securesocial.

phammer avatar phammer commented on July 3, 2024

Hi Jorge

Just a short update from my side. In order to clear the way for account linking, we went with the following data model (Mongo DB as persistence backend).

  • socialuser: we use the given object as "runtime user object", and do not store it directly in the DB.
  • user
    • lastLogin
    • loginCount
    • List[Account]
    • "further subobjects holding user related information such as contact information"
  • account
    • accountId (provider specific ID)
    • providerId (facebook, google, userpass)
    • lastLogin
    • loginCount
    • authMethod

Matching between a SocialUser and a user is done via account (account.accountId == socialUser.id.id && account.providerId). Linking is simple, i.e., it means a user has several accounts.

Having this data model, we have two nice features:

  • separation of runtime and persistence data
  • quite independent of securesocial, i.e., we can plugin securesocial without any customization.

But what would be really cool is to have a user trait that is used through out SecureSocial instead of an actual clase. For example, introduce "RuntimeUser" as trait and extend SocialUser with RuntimeUser. Having that, it would be even easier to customize SecureSocial to every projects need.

=> actually, if you agree. I could do the change (introduce the RuntimeUser trait) and sent a pull request.

Regards,
Patrick

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

@phammer thanks a lot for the update. Give me a couple of days to go over this. Having a busy week. I also need to consider how the Java API would work.

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

@phammer would you be willing to chat a few minutes about this? send me an email if interested.

from securesocial.

phammer avatar phammer commented on July 3, 2024

@jaliss did you got my invitation on linkedin? did not have your email address and didn't want to post mine here.

from securesocial.

poornerd avatar poornerd commented on July 3, 2024

Is this what you meant with "Introduced Identity trait" in the Change Log?

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

Not yet, but that will help because users will have different identities later.

from securesocial.

DrewEaster avatar DrewEaster commented on July 3, 2024

Is there any update on when account linking might appear in SecureSocial?

from securesocial.

mikenikles avatar mikenikles commented on July 3, 2024

+1 for an update as we're about to go down that path. Thanks

from securesocial.

almeidap avatar almeidap commented on July 3, 2024

+1 Waiting for an update on this as well. Thanks!

from securesocial.

cndreiter avatar cndreiter commented on July 3, 2024

+1 Also waiting for an update. Thanks

from securesocial.

mikenikles avatar mikenikles commented on July 3, 2024

We took @phammer's approach as a starting point and from there it's not a big deal to implement the rest. It works fine and if/when SecureSocial provides a built-in solution, I don't expect too much re-work to get our implementation changed.

from securesocial.

kotancode avatar kotancode commented on July 3, 2024

+1
I'm also in the camp where I have one internal account that can be mapped to multiple social network identities. I haven't implemented it yet, and would like to be able to do it as part of SecureSocial and not as a bolt-on or a hack.

from securesocial.

andrewswan avatar andrewswan commented on July 3, 2024

+1 for this enhancement please!

At the moment, if a person chooses to log into my application with say Google one day and Facebook the next, they will end up with two totally separate accounts, which is not good from a UX point of view.

P.S. Thanks for SecureSocial to start with, it's already saved me a lot of work!

from securesocial.

gmethvin avatar gmethvin commented on July 3, 2024

I'm really interested in this feature. I already have models set up in my application which should allow me to link multiple social users to a single user account.

Is there a hack/workaround I can use in the meantime (without completely forking SecureSocial)? It seems like I might be able to create my own providers and override the doAuth method to do what I want.

from securesocial.

forficate avatar forficate commented on July 3, 2024

I'm just looking in to @phammer solution.

I'm guessing this is implemented by a custom UserServicePlugin?

I can see how the User having a list of Accounts work. What I'm not understanding is a reasonable way to populate an existing User with a new Account object?

As an example:

I'm a new user, I sign in using facebook. My custom UserServicePlugin would call save creating a new User object with a new account linked to it.

Next time I visit the site I sign in with my Twitter account. I now have a brand new account but I'd like it to link to the old one.

This is where it gets complicated. When I sign in we get email Option[String] . I could see if this email address already exists under a account (if the email is provided), if it is found we can link it that way? Can we trust this email address to link against?

For Facebook / Linkedin providers I guess we can trust the email as they require email verification before enabling accounts. If it's a different provider there's potential for a malicious user to provide a email which isn't theres, when we then check our database and find a match with a existing user someone has just hijacked the account.

I'd ideally like linking to happen on sign in time if we detect common information, going through the above I'm not so sure now.

My second thought is to allow linking an account when signed in. This I think would be complex? Eg I login via facebook but have a previous twitter account, I'm thinking on the my account page have something to link the accounts. So I click a link twitter account button and then get given a twitter sign in, when authenticated if the twitter id returned matches an existing account object, it moves that account object to the new user as we can trust this id value. This then gives the issue of cleaning up any content associated to a user.

This get's a even bigger problem to solve the more I think about it, to do it in a clean secure way.

from securesocial.

kotancode avatar kotancode commented on July 3, 2024

Linking once already signed in is the only way I can see it being done reliably. My Facebook and twitter emails do not match, which is a common scenario. I may also have two twitter accounts, guaranteeing that they don't match.

What I envisioned is once you log in to create a new account, that is a master account with a unique id. If you then sign in to a second oauth account while there is still a root account id in your session, you get a linked account instead of a new one.

Sent from my iPhone

On Jun 15, 2013, at 5:35 PM, Adam Evans [email protected] wrote:

I'm just looking in to @phammer solution.

I'm guessing this is implemented by a custom UserServicePlugin?

I can see how the User having a list of Accounts work. What I'm not understanding is a reasonable way to populate an existing User with a new Account object?

As an example:

I'm a new user, I sign in using facebook. My custom UserServicePlugin would call save creating a new User object with a new account linked to it.

Next time I visit the site I sign in with my Twitter account. I now have a brand new account but I'd like it to link to the old one.

This is where it gets complicated. When I sign in we get email Option[String] . I could see if this email address already exists under a account (if the email is provided), if it is found we can link it that way? Can we trust this email address to link against?

For Facebook / Linkedin providers I guess we can trust the email as they require email verification before enabling accounts. If it's a different provider there's potential for a malicious user to provide a email which isn't theres, when we then check our database and find a match with a existing user someone has just hijacked the account.

I'd ideally like linking to happen on sign in time if we detect common information, going through the above I'm not so sure now.

My second thought is to allow linking an account when signed in. This I think would be complex? Eg I login via facebook but have a previous twitter account, I'm thinking on the my account page have something to link the accounts. So I click a link twitter account button and then get given a twitter sign in, when authenticated if the twitter id returned matches an existing account object, it moves that account object to the new user as we can trust this id value. This then gives the issue of cleaning up any content associated to a user.

This get's a even bigger problem to solve the more I think about it, to do it in a clean secure way.


Reply to this email directly or view it on GitHub.

from securesocial.

gmethvin avatar gmethvin commented on July 3, 2024

I agree with @kotancode. You can't rely on the email. You need to use something from a logged in user's session to link the accounts.

I've implemented my own version of linking accounts on top of SecureSocial. It seems like a bit of a hack, but here's how I did it:

  • I store the user ID (the user account in my application, not the social user ID) in the session while the user is logged in.
  • I wrote my own implementation of the Identity trait called UserIdentity which contains the user ID. This is essentially a wrapper for SocialUser.
  • I have a trait called UserIdentityProvider which overrides the authenticate method of the providers and creates a UserIdentity, and mix this in with all the providers I use.
  • In a custom implementation of UserService, I use the user ID in my custom UserIdentity to link the newly authenticated social user to an existing user account.

That said, when a user authenticates for the first time, you do probably want to check if the user's email matches another in the system and provide a way to link the accounts. This might be something you'd just want to allow users to provide a custom implementation for though. Making the controllers extensible classes instead of objects (particularly ProviderController) would help a lot for this sort of thing.

from securesocial.

kotancode avatar kotancode commented on July 3, 2024

Greg,
That's basically the hack I was planning on implementing I just haven't gotten around to it yet :)

If you could share any of that, it would be great!

Thanks,
Kevin

Sent from my iPhone

On Jun 15, 2013, at 10:43 PM, Greg Methvin [email protected] wrote:

I agree with @kotancode. You can't rely on the email. You need to use something from a logged in user's session to link the accounts.

I've implemented my own version of linking accounts on top of SecureSocial. It seems like a bit of a hack, but here's how I did it:

I store the user ID (the user account in my application, not the social user ID) in the session while the user is logged in.
I wrote my own implementation of the Identity trait called UserIdentity which contains the user ID. This is essentially a wrapper for SocialUser.
I have a trait called UserIdentityProvider which overrides the authenticate method of the providers and creates a UserIdentity, and mix this in with all the providers I use.
In a custom implementation of UserService, I use the user ID in my custom UserIdentity to link the newly authenticated social user to an existing user account.
That said, when a user authenticates for the first time, you do probably want to check if the user's email matches another in the system and provide a way to link the accounts. This might be something you'd just want to allow users to provide a custom implementation for though. Making the controllers extensible classes instead of objects (particularly ProviderController) would help a lot for this sort of thing.


Reply to this email directly or view it on GitHub.

from securesocial.

gmethvin avatar gmethvin commented on July 3, 2024

@kotancode Sure. The app isn't open source but I can provide a few snippets. Here's a gist with some of the code: https://gist.github.com/gmethvin/5794543

I also would like to have a way to offer to link accounts when I think the user might have another user on the system (e.g. if the user has the same email). If it were possible to override the methods of ProviderController, I think this would be easy to customize, but I'm not sure how best to do it now.

from securesocial.

andrewswan avatar andrewswan commented on July 3, 2024

@gmethvin You guys are obviously working in Scala. I was wondering how a Java-based Play developer would go about linking multiple social accounts to the same user. I tried modifying my BaseUserService subclass so that it could detect if a user was already logged in, and if so, add the social account (if new) to that existing user. The code (or pseudo code in some places) looks as follows:

@Override
public Identity doSave(final Identity identity) {
    final UserId userId = identity.id();
    // In my data model, one User can have many Account instances
    final Account existingAccount = getAccountByUserId(userId); // this works
    if (existingAccount == null) {
        // This account is unknown to the application
        final Identity loggedInIdentity = SecureSocial.currentUser(); // FAILS (no HTTP context)
        if (loggedInIdentity == null) {
            LOGGER.debug("Creating new User with UserId '{}'", userId);
            // TODO store a new User and Account in the db
        }
        else {
            User existingUser = getUserFromIdentity(loggedInIdentity); // TODO implement this
            Account newAccount = Account.newFromIdentity(loggedInIdentity);
            // TODO add new account to existing user and save it in the db
        }
    }
    else {
        // This account is already known to the application (and therefore linked to a User)
    }
    return identity;
}

My problem is that the call to SecureSocial.currentUser() fails with the following error:

java.lang.RuntimeException: There is no HTTP Context available from here. at play.mvc.Http$Context.current(Http.java:30) ~[play_2.10.jar:2.1.1] at securesocial.core.java.SecureSocial.currentUser(SecureSocial.java:133) ~[securesocial_2.10-master-SNAPSHOT.jar:master-SNAPSHOT] at services.PersistentUserService.doSave(PersistentUserService.java:53) ~[classes/:na] at securesocial.core.java.BaseUserService.save(BaseUserService.java:88) ~[securesocial_2.10-master-SNAPSHOT.jar:master-SNAPSHOT] at securesocial.core.UserService$$anonfun$save$2.apply(UserService.scala:169) ~[securesocial_2.10-master-SNAPSHOT.jar:master-SNAPSHOT] at securesocial.core.UserService$$anonfun$save$2.apply(UserService.scala:169) ~[securesocial_2.10-master-SNAPSHOT.jar:master-SNAPSHOT]

Is there any way in Java for a BaseUserService subclass to detect whether a user is already logged in?

from securesocial.

gmethvin avatar gmethvin commented on July 3, 2024

@andrewswan This would be ugly, but you could have the same logic I have in the UserIdentityProvider#authenticate method in a static helper method that takes a provider and a request. You'll have to use scala types like Either in your Java code, but I think it would work.

from securesocial.

chrisbeach avatar chrisbeach commented on July 3, 2024

+1 interested in this feature

from securesocial.

nelsonblaha avatar nelsonblaha commented on July 3, 2024

Sounds like many of you have figured out how to do this, and that Identity has been implemented to make it a little easier. I'm just getting started with Play, but I'm going to attempt it from what's supplied here. Would love to see it supported.

from securesocial.

mkbehbehani avatar mkbehbehani commented on July 3, 2024

I want this as well, and I'm hoping someone with massive power of the internets can create it.

Good luck, we're all counting on you.

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

I just updated master-SNAPSHOT and included this feature. Please see the sample apps to see how that is being done and use it as a guide for your own apps. I'll close this issue but please open new ones if issues arise with the new implementation.

Thanks!

from securesocial.

andrewswan avatar andrewswan commented on July 3, 2024

Super-excited to try this out - thanks heaps @jaliss !

from securesocial.

andrewswan avatar andrewswan commented on July 3, 2024

Please see the sample apps to see how that is being done

Jorge, could you please give a little more detail about which classes we should look at? I've looked in samples/java and samples/scala, but nothing jumps out at me. Are your changes on master or some other branch?

from securesocial.

jaliss avatar jaliss commented on July 3, 2024

Yes. Changes are in the master branch.

There is a new link method that does the account linking. The difference is how the UserService is implemented.

When you save an identity you should also create a new user (basically a an id) so you can group all the identities for a given user.

If you compare the new sample user service implementations with the old ones it should be clearer. In the previous samples an Identity is a user. In the new samples before you can save an identity you need to create the user that will own it.

Hope this clarifies a bit.

On 6 Feb 2014, at 00:46, Andrew Swan [email protected] wrote:

Please see the sample apps to see how that is being done

Jorge, could you please give a little more detail about which classes we should look at? I've looked in samples/java and samples/scala, but nothing jumps out at me. Are your changes on master or some other branch?


Reply to this email directly or view it on GitHub.

from securesocial.

nelsonblaha avatar nelsonblaha commented on July 3, 2024

Source for link UserService example: 6c8f139

from securesocial.

abhishekShukla avatar abhishekShukla commented on July 3, 2024

Hi,

I was looking at the sample code for linking two accounts together.

I was wondering what happens or what should happen in the following flow:

  1. I login using Facebook. (new user ID is created). I do my stuff and logout.
  2. I login using Twitter. (Again a new user ID is created). I do my stuff and logout.
  3. I login using Facebook. Now I try to link my Facebook and Twitter accounts.

def link(CURRENT: Identity, TO: Identity)

I guess you could do the following:

  1. Check if the TO Identity Id already exists. If it does, it will have its own application user ID.
  2. Change that application user ID to CURRENT's application user ID

Have I misunderstood anything?
Is this acceptable behavior? Is there a better way to do this?

from securesocial.

peteoleary avatar peteoleary commented on July 3, 2024

Here's what I did, seems to work fine for now:

  1. User authenticates through the SecureSocial login page using Github, Facebook, Google, whichever.
  2. New user gets a "base" User record in my DB. I generate a unique ID for this record which is not the provider ID.
  3. On an application page, user is invited to link other providers. When they authenticate, the link method is called with "current" and "to": I create a new User record with a "linkedTo" pointer back to the original login User record.
  4. Now the user has multiple DB records which all point back to the same original login record where I can fetch my internal unique ID.
  5. Anytime you see a save() or link(), always check first to see if the provider/id combination already exists. In your UI, you should give the user feedback whether they have already linked to a provider.

This scheme has the advantage that the user can now login in using any linked provider.

from securesocial.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.