Announcement Announcement Module
No announcement yet.
spring social lifecycle Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • spring social lifecycle

    Hello, i am new to spring social module and i am trying to sso with fb. I need to have better insight in the lifecycle of the social module. Can someone point out what exactly is on the stack-trace when i click sign in using the spring social. I noticed that there are couple of sections:

    1. After the user clicks the sign in button spring's ProviderSignInController fetches the request and redirects the user to the login page of the provider (for e.g. facebook's login page) and instructs it when the user logs-in successfully to return to a given url (have't tried what happens if i am not logged in successfully, any hints here?).

    2. I guess next is the Interceptor which checks if the user is already signed in and if that holds true it just returns true and passes on control to the next object in the chain.. If the user is not signed in the method requireSignIn(req, resp) is called which actually creates new RedirectView("/signin", true).render(null, request, response) and returns false. I guess this is actually performing the redirection to /signin and returns false just to stop the execution of servlets/filters that come next in the chain. Anyway i can't quite understand this (this is the quickstart example for sso with fb):

    This is in the preHandle method of the UserInterceptor:

    rememberUser(request, response);
    handleSignOut(request, response);
    if (SecurityContext.userSignedIn() || requestForSignIn(request)) {
    return true;
    } else {
    return requireSignIn(request, response);

    Why in the if statement first it's checked if the user is signed in and if he's not and request for sign in then the method returns true..? Is it that the preHandler should return true or false to stop executing next servlet/filter in the chain?

    3. Next spring fetches stuff returned from fb, access_token for sure and other possibly, and tries to call the class which implements the SignInAdapter which has to actually recieve the api of the provider wrapped in the Connection class.. And here is where i do the signing in with my app (using my services and db queries).. If i can't sign him in i return the /signin/facebook url again and if i sign him in successfully i return him to the homepage as logged user..

    Now my question is, where does ConnectionSignUp comes in, is it before my SignInAdapter is called, and i assume if that's true i need to check if the user is in my db with the provided id, and if he's not i should perform silent signup so that next SignInAdapter can sign in the user just previously added in the ConnectionSignUp's callback method.

    So i need to get the lifecycle of the callback methods of various components in the social module. This way i can know where i should put my code that checks and updates my app db corectly.

    Ahh yeah, one more question.. The userId that is send to the callback methods of ConnectionSignUp for e.g. is that the id returned from the social-network, for e.g. facebook id? I can quite find where this id is extracted from.. I assume this has to do something with the ProviderSignInController..


  • #2
    Here's the gist of it:
    - ProviderSignInController handles the request to /signin/{provider ID}.
    - If it's an OAuth 1 provider, it fetches a request token next.
    - Then, regardless of whether it's OAuth 1 or OAuth 2, it redirects to the provider's signin page.
    - At that point, if the user is already signed into the provider, it will prompt the user to authorize the app. If the user isn't signed into the provider, it will prompt the user to sign in and then authorize the app. Note that all of this step takes place at the provider and the behavior here is defined by the provider (and is different for Facebook, Twitter, LinkedIn, etc)
    - After the user authorizes the app, the provider redirects back to the app, where ProviderSignInController receives the callback.
    - ProviderSignInController uses what it receives from the callback (it differs depending on whether it's OAuth 1.0 vs. OAuth 1.0a vs. OAuth 2) to retrieve an access token.
    - ProviderSignInController fetches the user's identifying information from the provider (usually a numeric ID...that's certainly what it is with Facebook).
    - ProviderSignInController compares that user's provider ID with existing connections in the database.
    - If an existing connection matches, then the local user belonging to that connection is signed in via the SignInAdapter. The SignInAdapter exists so that you can implement any security mechanism you want and so that Spring Social isn't coupled to Spring Security.
    - If no existing connection matches, then ProviderSignInController will place the connection details in session (as a ProviderSignInAttempt) then redirect to the application-provided signup (aka, registration) page.
    - After the user registers, the application can use ProviderSignInUtils to create a connection between the newly registered user and the provider using the ProviderSignInAttempt that was placed in session.

    I assume that you're looking at the spring-social-quickstart example. In that example UserInterceptor is just a simple (somewhat hackish) approach to application security since the sample doesn't use Spring Security. In other samples, such as Spring Social Showcase, Spring Security *is* in play, so there is no such interceptor. My point here is to not place too much emphasis on UserInterceptor as it's just for that sample and not really part of Spring Social.

    ConnectionSignUp comes into play when you want to implicitly sign in a user. It's optional (and other samples such as spring-social-showcase don't use it). The idea is that your app doesn't necessarily keep a database of existing users and instead wants to use whatever info it receives from the provider as user data. In the case of spring-social-quickstart, there is no user database, but when the user authorizes with Facebook, the user's Facebook data is retrieved and used to create a user on-the-fly and without going through a signup screen. The call to ConnectionSignUp happens in JdbcUsersConnectionRepository when the connection data is being used to try to find an existing connection in the DB--if no connection can be found and if the ConnectionSignUp is not null, then it will create the user and a connection on-the-fly. Again, this feature is optional.

    (Note: As JdbcUsersConnectionRepository is currently the only implementation of UsersConnectionRepository, it's handy to have the code for working with ConnectionSignUp in there. There's opportunity for refactoring to extract common code such as this from JdbcUsersConnectionRepository into a base class for other non-JDBC-based implementations to work with.)

    The ConnectionSignUp isn't given just a user's given a Connection. That Connection includes some details in ConnectionData, among which is providerUserId, which is the user's ID on the provider (e.g., their Facebook ID). That information is ultimately populated from each provider's implementation of ApiAdapter (it's FacebookAdapter in the case of Facebook).

    ConnectionSignUp's execute() method also returns a user ID. In that case, the ID it returns is the local application's ID for the user that it creates on-the-fly. In the quickstart example, it's rather simplistic, generating the ID from an AtomicLong, but your implementation of the ConnectionSignUp interface could do whatever you want (you could even go so far as to actually write a record to the database for the on-the-fly user and return the primary key as the ID).