Search code examples
spring-securityoauth-2.0sap-commerce-cloud

Auto login to Hybris web application based on OAuth2 access token


Background
We have a website running using SAP Hybris commerce, where users can log in (basic Spring Security) and browse the site. We also have a native mobile app, which will again authenticate the user in the Hybris system using Oauth2 and work stateless.

Problem statement
The user is logged in a mobile native app and needs to perform some authenticated operations on the web, in a standard web browser (ie. using some features not supported by native apps yet). The native app should open the browser and make sure the user is logged into the browser with the same account he/she has in the native app.

Current web security-config.xml

<http access-decision-manager-ref="accessDecisionManager" use-expressions="false">
    <session-management session-authentication-strategy-ref="fixation"/>
    <intercept-url pattern="/login.jsp" access="PERMIT_ALL"/>
    <intercept-url pattern="/**" access="HYBRIS_NOT_INITIALIZED,ROLE_CUSTOMERGROUP"/>
    <http-basic />
    <form-login 
        always-use-default-target="false" 
        login-page="/login.jsp" 
        username-parameter="j_username"
        password-parameter="j_password"
        login-processing-url="/j_spring_security_check"
        authentication-failure-url="/login.jsp?login_error=1"
    />
    <remember-me services-ref="rememberMeServices" key="adminweb"/>
    <logout logout-url="/j_spring_security_logout" logout-success-url="/login.jsp"/>
    <csrf />
    <headers>
        <frame-options disabled="true"/>
    </headers>
</http>

Oauth2 config

<!-- Generating token -->
    <sec:http pattern="/oauth/token" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
              authentication-manager-ref="clientAuthenticationManager" use-expressions="false">
        <sec:csrf disabled="true"/>
        <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" requires-channel="${webservicescommons.required.channel:https}"/>
        <sec:anonymous enabled="false" />
        <sec:port-mappings>
            <sec:port-mapping http="#{configurationService.configuration.getInt('tomcat.http.port',9091)}"
                              https="#{configurationService.configuration.getInt('tomcat.ssl.port',9092)}" />
            <sec:port-mapping http="#{configurationService.configuration.getInt('embeddedserver.http.port',9091)}"
                              https="#{configurationService.configuration.getInt('embeddedserver.ssl.port',9092)}" />
        </sec:port-mappings>
        <sec:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
        <sec:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
        <sec:access-denied-handler ref="oauthAccessDeniedHandler" />
        <sec:headers>
            <sec:frame-options disabled="true"/>
        </sec:headers>
    </sec:http>

<!-- Accessing APIs using V2 -->
    <http pattern="/v2/**" entry-point-ref="oauthAuthenticationEntryPointV2"
              access-decision-manager-ref="webSecurityAccessDecisionManager"
              xmlns="http://www.springframework.org/schema/security" create-session="stateless">

            <anonymous username="anonymous" granted-authority="ROLE_ANONYMOUS"/>
            <!--<session-management session-authentication-strategy-ref="fixation"/>-->

            <intercept-url pattern="/**" requires-channel="https"/>

            <port-mappings>
                <port-mapping http="#{configurationService.configuration.getProperty('tomcat.http.port')}"
                              https="#{configurationService.configuration.getProperty('tomcat.ssl.port')}"/>
                <port-mapping http="#{configurationService.configuration.getProperty('embeddedserver.http.port')}" 
                              https="#{configurationService.configuration.getProperty('embeddedserver.ssl.port')}" />
            </port-mappings>

            <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
            <access-denied-handler ref="oauthAccessDeniedHandlerV2"/>

            <headers >
                <content-type-options />
                <hsts include-subdomains="true" max-age-seconds="16070400" />
                <xss-protection />
                <security:frame-options disabled="true"/>
            </headers>
            <security:csrf disabled="true"/>
        </http>

Questions

  1. How to modify the web security config so that whenever there is an access-token request parameter it authenticates the user based on access-token and creates the session for the same user.
  2. I'm thinking to have public controller mapping like /login/autologin?token=<token>&redirect=<url> which basically authenticates the user and calls the autologin strategy. But, I don't know, what all classes/strategies I need to call to authenticate the user using access-token here and how?

Any other suggestion to achive this?


Solution

  • I have managed this requirement something like this

    1. Write a controller which capture the access_token and call below TokenAuthenticationValidator

    2. Write a TokenAuthenticationValidator by referring OAuth2AuthenticationProcessingFilter where you need to extract the token base authentication object and pass it to OAuth2AuthenticationManager to authenticate it.

    3. If the token is authenticated, call the autoLoginStrategy which autologin the user. You need to write your custom autoLoginStrategy, which autologin the user without a password check. Like

      oauthUserAutoLoginStrategy.login(authResult.getPrincipal().toString(), request, response);