I am writing this blog, to give overview on how I implemented SSO to JIRA using PingFederate Federation Server. The end client LDAP was already on PingFederate that is why they wanted JIRA SSO to integrate using the same PingFederate. When I stared work, following were the Workflow and certain assumptions:
  • User exists in Active Directory
  • User are Authenticated using Ping Identity
  • You have the agent-config.txt file. You get this file when you set up adapter for JIAR In PF server.
  • Users are currently able to login to JIRA when the same username exists in JIRA.
  • SSO has been achieved through the TokenJiraAuth class which extends JiraSeraphAuthenticator
  • SSO with OpentokenJiraAuth, when users are manually added to JIRA or already exits.
  • Ping Identity provides information from AD about the User to OpentokenJiraAuth.
  • OpentokenJiraAuth only uses username and session to validate the user
  • When a user logs into JIRA through Ping Identity SSO, the OpentokenJiraAuth should check the JIRA User database to see if the username provided by Opentoken already exits
  • If the username does not exist, the User record is inserted with username, real name, and email
  • This all happens before the user is redirected to the JIRA homepage.
Steps to implement the SSO: 1- Copy the following files to the atlassian-jira/web-inf/lib
  1. opentoken-agent-2.4.jar (Other library needed)
  2. commons-beanutils.jar
  3. commons-collections-3.2.jar
  4. log4j.jar
2-    Now we will implement our SSO class which will extend the JiraSeraphAuthenticator
package com.pingidentity.opentoken.jira;
public final class TokenJiraAuth   extends JiraSeraphAuthenticator
{
private static final long serialVersionUID = 3452011252741183166L;
private AgentConfiguration agentConfig;
public Principal getUser(HttpServletRequest request, HttpServletResponse response)
{
Principal user = null;
String agentConfigLocation = "/agent-config.txt";
try
{
InputStream agentConfigStream;
InputStream agentConfigStream;
if (agentConfigLocation.startsWith("classpath:"))
{
agentConfigLocation = agentConfigLocation.substring(10);
 
agentConfigStream = getClass().getResourceAsStream(agentConfigLocation);
}
else
{
agentConfigStream = new FileInputStream(agentConfigLocation);
}
this.agentConfig = new AgentConfiguration(agentConfigStream);
 
String strTokenName = this.agentConfig.getTokenName();
 
Agent otkAgent = new Agent(this.agentConfig);
request.getSession(true);
if ((request.getSession() != null) && (request.getSession().getAttribute("seraph_defaultauthenticator_user") != null))
{
user = (Principal)request.getSession().getAttribute("seraph_defaultauthenticator_user");
}
else
{
String strOTKParam = request.getParameter(strTokenName);
if (strOTKParam != null)
{
Map userInfo = otkAgent.readToken(request);
if (userInfo != null)
{
String strSubject = (String)userInfo.get("subject");
if (strSubject != null) {
try
{
user = getUser(strSubject);
request.getSession().setAttribute("seraph_defaultauthenticator_user", user);
request.getSession().setAttribute("seraph_defaultauthenticator_logged_out_user", null);
System.out.println("All set");
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
return null;
}
}
else {
return null;
}
}
else
{
return null;
}
}
else
{
return null;
}
}
}
catch (TokenException e)
{
System.out.println("Token Error is " + e.getMessage());
e.printStackTrace();
}
catch (FileNotFoundException eFile)
{
System.out.println("File Not Found Exception. Error is " + eFile.getMessage());
eFile.printStackTrace();
}
catch (SecurityException eSecurity)
{
System.out.println("Security Exception. Error is " + eSecurity.getMessage());
eSecurity.printStackTrace();
}
catch (IOException e)
{
System.out.println("Unable to load OpenToken agent configuration file (" + agentConfigLocation + ").  Error: " + e.getMessage());
}
return user;
}
Compile the class & put at exact package path inside atlassian-jira/web-inf/classes 3- put the agent-config.txt file at the same location “atlassian-jira/web-inf/classes” 4- GO to path atlassian-jira\WEB-INF\classes\ and edit file “seraph-config.xml” Comment the yellow highlighted entry and put the new authenticator.
<!– CROWD:START – If enabling Crowd SSO integration uncomment the following SSOSeraphAuthenticator and comment out the JiraSeraphAuthenticator below –> <!–  –> <authenticator class=”com.pingidentity.opentoken.jira.TokenJiraAuth”/> <!– CROWD:END –> <!– CROWD:START – The authenticator below here will need to be commented out for Crowd SSO integration –> <!– <authenticator class=”com.atlassian.jira.security.login.JiraSeraphAuthenticator”/> –> <!– CROWD:END –> Restart the Jira service .Check for the existing JIRA user.
Once user login to the PF Adapter URL and if user exists in the JIRA, then user will be redirecetd to JIRA dashboard. In addition, you can always write your own logic to create user on the fly in the TokenJiraAuth.java file. Hope this article will help you, if you looking to integrate SSO to JIRA. This article should also give you direction, even with OneLogin SSO integertaion or any other type. Cheers! That is all for this article, in case you need Salesforce Implementation Services for any Salesforce related work, then please feel free to reach out to sales@girikon.com

About Author
Nirupama Shree
Nirupama Shree is currently working as a Business Analyst at Girikon, managing projects related to Salesforce. She has work experience in requirement gathering, blogging, maintaining client relations and has experience in technologies like Salesforce, Magento, Opencart. In her leisure time, she loves listening to music.
Share this post on: