By: Andrew Sciberras user 03 Feb 2015 at 10:18 p.m. CST

2 Responses
Andrew Sciberras gravatar
Hello I have been trying to get a grasp on the workflow associated with custom authenticators, but I just can't seem to get it to work. I'm trying to provide an OIDC service that uses LinkedIn to authenticate a user. LinkedIn provide quite an easy to use OAuth2 based interface. The short version of this question is: if my authentication process redirects the user to an external site to obtain an authorization code, where should that authorization code get sent to allow Gluu to contain the process of authenticating the user? The longer explanation is this: My desired user interaction is: 1. User is sent to Gluu with an auth_mode identifying the linkedin authentication mode 2. User is redirected to linkedin, whereby the url is requesting an authorization code. 3. The user authenticates and consents in LinkedIn, and linked in creates an authentication code and sends it *somewhere*. 4. The custom authentication process continues and the authorization code is obtained. This code is provided to linkedin and an access token is obtained. 5. The access token is used in a rest call to linkedin to obtain the user's email address. 6. The gluu identity associated with the email address is looked up, and if a single person is located they become the authenticated identity. 6a. If zero, or more than one identity is located in association with the linkedin email the process failed - I don't care about correlating accounts or just-in-time provisioning. I realise that within Gluu I need to create a custom authentication method and implement the relevant jython methods. Additionally, I also know that I need to update the oxauth.war file with (for example) linkedin/linkedinlogin.xhtml and linkedin/linkedinlogin.page.xml files. So far I have completed the above steps. In my implementation I set the getPageForStep (step 1) to return "/auth/linkedin/linkedinlogin.xhtml". For example (ignore the lack of indenting): `def getPageForStep(self, configurationAttributes, step):` ` print "LinkedIn page for step %d" % (step)` ` if (step == 1):` ` return "/auth/linkedin/linkedinlogin.xhtml"` ` ` I also have a prepareForStep function that sets a variable to the desired redirect url. For example: ` def prepareForStep(self, configurationAttributes, requestParameters, step):` ` print "LinkedIn prepare for step %d" % (step)` ` context = Contexts.getEventContext()` ` if (step == 1):` ` context.set("test_redirect_uri", "https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=75lwtdkwp9pish&scope=r_emailaddress%20r_fullprofile&state=randomState&redirect_uri=https://ec2-54-66-158-132.ap-southeast-2.compute.amazonaws.com/oxauth/auth/linkedin/linkedin-login")` Within "/auth/linkedin/linkedinlogin.page.xml" I set a <redirect> to redirect the user to LinkedIn to obtain an authorization code. For example: `<?xml version="1.0" encoding="UTF-8"?>` `<page xmlns="http://jboss.com/products/seam/pages"` ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"` ` xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"` ` view-id="/auth/linkedin/linkedinlogin.xhtml">` ` ` ` <action execute="#{authenticator.prepareAuthenticationForStep}" on-postback="false" if="#{not identity.loggedIn}"/>` ` ` ` <rewrite pattern="/auth/linkedin/linkedin-login" />` ` ` ` <navigation from-action="#{authenticator.prepareAuthenticationForStep}">` ` <rule if-outcome="success">` ` <redirect url="#{test_redirect_uri}"/>` ` </rule>` ` ` This successfully achieves items #1, 2, and 3 in my desired user interaction above. My problem however is that I don't know where I should get LinkedIn to send the authorization code, such that the next thing that Gluu does is call the authenticate() method within my custom authenticator and begin to process the remaining steps. In my latest attempt, I have instructed LinkedIn to deliver the code to /oxauth/auth/linkedin/linkedin-login, but this doesn't seem to work. Are you able to provide any guidance as to how I should approach this issue? I have looked at examples, however they seem to be missing this piece of information regarding where what should be used as the redirect uri for an external oauth client. Thanks Andrew.

By Yuriy Movchan staff 04 Feb 2015 at 1:43 a.m. CST

Yuriy Movchan gravatar
Hi Andrew, There is special page in oxAuth which allows to resume authentication process after getting authorization code: /postlogin . This is empty page which just call "#{authenticator.authenticateWithOutcome}" to continue process. But before redirecting to LinkedIn for authentication you should call next method: ` print "LinkedIn prepare for step 1. Store current oxAuth authentication context in session" authenticationService.storeRequestParametersInSession() ` On getting request to /postlogin oxAuth should restore stored authentication context automatically. I recommend to take a look on Google authentication module [Google person authentication module](https://github.com/GluuFederation/oxAuth/tree/master/Server/integrations/gplus) . It uses oxAuth client to prepare oxAuth requests. For example: ` def getTokensByCode(self, currentClientSecrets, configurationAttributes, code): def getUserInfo(self, currentClientSecrets, configurationAttributes, accessToken): ` You also can use it use for authorization request too. Regards, Yuriy

By Andrew Sciberras user 04 Feb 2015 at 3:55 p.m. CST

Andrew Sciberras gravatar
Thanks Yuriy, your answer was very helpful and worked well. Andrew