Hi folks.
Just recently I had to implement SSO to a tomcat-based JSP application, so that a portal user doesn't have to logon twice. As you all know, SAP's standard technology to implement SSO is the use of a cookie called SAP Logonticket. You may also know, that there are two supported ways to implement SSO to Non-SAP applications, using a native library for ticket verification or using a web server filter. (help.sap.com )
I decided to use the library SAPSSOEXT. On my search for documentation, I found out, that the guide I knew from SDN disappeared and the rest of the official documentation is,.. uh, let's say a bit rudimental.
So, here is a brief instruction from my side, maybe some of you will need it as well.
1. Get the required dynamic link libraries.
Go to http://service.sap.com/patches -> Entry by Application Group -> Additional Components
Get the versions of SAPSECULIB and com.mysap.sso.SSO2Ticket
package com.mysap.sso;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
public class SSO2Ticket {
public static final int ISSUER_CERT_SUBJECT = 0;
public static final int ISSUER_CERT_ISSUER = 1;
public static final int ISSUER_CERT_SERIALNO = 2;
private static boolean initialized = false;
public static String SECLIBRARY;
public static String SSO2TICKETLIBRARY = "sapssoext";
private static List pseudoACL;
static {
pseudoACL = new ArrayList();
pseudoACL.add("EP7|000|OU=J2EE, CN=S1D|OU=J2EE, CN=EP7|00");
if (System.getProperty("os.name").startsWith("Win")) {
SECLIBRARY = "sapsecu.dll";
} else {
SECLIBRARY = "libsapsecu.so";
}
try {
System.loadLibrary(SSO2TICKETLIBRARY);
System.out.println("SAPSSOEXT loaded.");
} catch (Throwable e) {
System.out.println("Error during initialization of SSO2TICKET:\n"+ e.getMessage());
}
}
/**
Initialization
@param seclib location of ssf-implemenation
@return true/false whether initailisation was ok
*/
protected static native synchronized boolean init(String seclib);
/**
Returns internal version.
@return version
*/
public static native synchronized String getVersion();
/**
eval ticket
@param ticket the ticket
@param pab location of pab
@param pab_password password for access the pab
@return Object array with:
*/
public static native synchronized Object[] evalLogonTicket(String ticket,String pab,String pab_password) throws Exception;
/**
Parse certificate
@param cert Certificate received from evalLogonTicket
@param info_id One of the requst id´s
@return Info string from certificate
*/
public static native synchronized String parseCertificate(byte[] cert,int info_id);
/**
@param request HttpServletRequest
@param pathToPSE Path to PSE
@return String array with:
@throws LogonTicketException
*/
public static synchronized String[] verify(HttpServletRequest request, String pathToPSE) throws LogonTicketException
{
String[] ticketContent = null;
if(!initialized) {
init("sapsecu.dll");
initialized = true;
}
String ticket = null;
Cookie[] all_Cookies = request.getCookies();
int i = 0;
int j = 0;
if (all_Cookies != null) j = all_Cookies.length;
for (i = 0; i < j; i++) {
//Get MYSAPSSO2 cookie from request context...
if ("MYSAPSSO2".equals(all_Cookies[i].getName())) {
ticket = all_Cookies[i].getValue();
break;
}
}
if(ticket==null) throw new LogonTicketException(LogonTicketException.NO_TICKET_FOUND); // mysapsso2 cookie not found
Object[] o = null;
try {
o = SSO2Ticket.evalLogonTicket(ticket, pathToPSE, null);
byte[] cert_ = (byte[]) o[3];
ticketContent = new String[9];
ticketContent[0] = (String)o[0]; //First element is the SAP system user
ticketContent[1] = (String)o[1]; //Second element is the id of the issuing system
ticketContent[2] = (String)o[2]; //Third element is the client of the issuing system
ticketContent[3] = (String)o[4]; //Portal user
ticketContent[4] = (String)o[5]; //Authscheme
ticketContent[5] = (String)o[6]; //Validity in seconds
ticketContent[6] = SSO2Ticket.parseCertificate(cert_, SSO2Ticket.ISSUER_CERT_SUBJECT);
ticketContent[7] = SSO2Ticket.parseCertificate(cert_, SSO2Ticket.ISSUER_CERT_ISSUER);
ticketContent[8] = SSO2Ticket.parseCertificate(cert_, SSO2Ticket.ISSUER_CERT_SERIALNO);
String aclStr = ticketContent[1]"|"ticketContent[2]"|"ticketContent[6]"|"ticketContent[7]"|"ticketContent[8];
if(!pseudoACL.contains(aclStr)) throw new LogonTicketException(LogonTicketException.TICKET_ISSUER_NOT_TRUSTED);
} catch (Exception e) {
LogonTicketException ex = new LogonTicketException(LogonTicketException.TICKET_VERIFICATION_FAILED);
ex.initCause(e);
throw ex;
}
return ticketContent;
}
}
>
com.mysap.sso.LogonTicketException
package com.mysap.sso;
/**
@author Karsten Geiseler
*/
public class LogonTicketException extends Exception {
public static final String NO_TICKET_FOUND = "No ticket found";
public static final String TICKET_VERIFICATION_FAILED = "Ticket verification failed";
public static final String TICKET_ISSUER_NOT_TRUSTED = "Ticket Issuer not trusted";
public LogonTicketException() {
super();
}
public LogonTicketException(String message) {
super(message);
}
public LogonTicketException(Throwable cause) {
super(cause);
}
public LogonTicketException(String message, Throwable cause) {
super(message, cause);
}
}
Now modify the SSO2Ticket class according to your needs.
I demonstrated a simple access control list to list trusted ticket issuers. Add your trusted issuers there or implement a more sophisticated solution.
Feel free to add your own logging implementation.
Do not move the classes to a different package!
4. Get your issuing portal's certificate in a pse file
Log on to your portal, go to System Administration -> System Configuration -> Keystore Administration and download the verify.pse file.
On your non-SAP system, put the file somewhere on the filesystem. The path to the file is an input variable for SSO2Ticket.verify(HttpServletRequest request, String pathToPSE). In my example the path will be C:
tmp
verify.pse
If you want to verify tickets of more than one issuing system, you have to store the X.509 certificates of each issuing system in a pse file. How this can be accomplished is described in SAP Note 722072.
5. Now you can call SSO2Ticket.verify(HttpServletRequest request, String pathToPSE)
Here is a jsp sniplet to show the usage of the classes:
<%
try
{
String[] ticketContent = com.mysap.sso.SSO2Ticket.verify(request,"C:
tmp
SAPSSOEXT
NTintel
ssosample
java
verify.pse");
%>
<%=ticketContent[0]%><br>
<%=ticketContent[1]%><br>
<%=ticketContent[2]%><br>
<%=ticketContent[3]%><br>
<%=ticketContent[4]%><br>
<%=ticketContent[5]%><br>
<%=ticketContent[6]%><br>
<%=ticketContent[7]%><br>
<%=ticketContent[8]%><br>
<%
} catch (com.mysap.sso.LogonTicketException e)
{ %>
<%=e.getMessage()%>
<% } %>
</textarea> <p>That's it. The verify method returns the ticket content as a String array, the portal's userId is ticketContent[3].</p><p>Cheers, Karsten</p>
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 3143 | |
| 1916 | |
| 1916 | |
| 1213 | |
| 1081 | |
| 757 | |
| 755 | |
| 742 |