cancel
Showing results for 
Search instead for 
Did you mean: 

How to define the CallbackHandler in programmatic authentication

Former Member
0 Kudos

Hi there,

we have an own authentication stack named "ticket" and want to trigger its checks programmatically in a servlet, serving as a kind of gatekeeper and redirecting to the proper URL if login was sucessful. According to the documentation, this is one of two options ("programmatically" vs. "configured").

Since I didn't find an appropriate code sample, I tried to figure it out on my own:

protected void doPost(
  HttpServletRequest request,
  HttpServletResponse response)
    throws ServletException, IOException {

    try {
      LoginContext lc = new LoginContext(authenticationStack);
      lc.login();								
     String redirectURL = getRedirectURL(request);
     response.sendRedirect(redirectURL);
      } 
    catch (LoginException le) {
      ...
      }		  	

  }

When the servlet is called, we get the error:


Error: No CallbackHandler available to garner authentication information from the user. ticket

I guess that the CallbackHandler has to somehow pass the HTTP request object to the authentication layer. I have seen that there is a constructor for LoginContext having a callbackHandler as second argument. But I wonder what to fill in there.

Can someone help me what to fill in for "callbackHandler"? Is there a sample code containing an implementation of this interface for this very simple and straightforward servlet case?

Thanks and regards,

Rüdiger

Accepted Solutions (0)

Answers (1)

Answers (1)

Former Member
0 Kudos

I don't close the message yet. But it seems I found the essential part of the answer. SAP's standard callback handler can be accessed by


new com.sap.security.core.logon.imp.SAPJ2EECallbackHandler(request,response)

I can fill this into my login context constructor:

try {
  SAPJ2EECallbackHandler sch = new SAPJ2EECallbackHandler(request, response);
  LoginContext lc = new LoginContext(authenticationStack, sch);
  lc.login();								
  String redirectURL = getRedirectURL(request);
  response.sendRedirect(redirectURL);
  }   catch (LoginException le) {
// Fallback for Basic Authentication, 
// if first attempt to login didn't work (BASIC is part of our stack)
          response.setHeader( "WWW-Authenticate", authenticationRealm);
          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
          }

I will do some tests. I will not close this message before having found that this really solves the problem.

Former Member
0 Kudos

The tests were positive. The above code will go productive.

Just for documentation purposes, before finally deleting unused code parts, I copy them into this thread:

Invoking a single authentication method, not a complete stack

This can be achieved with code similar to the following:

/* Einzelne Anmeldung, kein ganzer Stack!!! */
ILogonAuthentication authenticator = UMFactory.getLogonAuthenticator();;
  try {			    	
    authenticator.logon(request, response, authenticationStack);
   String redirectURL = getRedirectURL(request);
   response.sendRedirect(redirectURL);
  } catch (LoginException e) {
        response.setHeader( "WWW-Authenticate", authenticationRealm);
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 
            "SRM-Anmeldung '" + authenticationStack + "' fehlgeschlagen");  	        	
        }

A callback handler for test purposes

If you want to know which callbacks are triggered by your authentication stack, you can define your own callback handler and pass it to the login context instead.

I worked with a local (inner) class for this purpose. I had to use reflection to dynamically call a "getName" method, since the actual callback classes where partly hidden.

/* Wird nicht mehr benötigt, wir können direkt den SAPJ2EECallbackHandler instanziieren */
private static class TheCallbackHandler implements CallbackHandler {
		
  private HttpServletRequest request;
  private HttpServletResponse response;
			
  private TheCallbackHandler(HttpServletRequest request, HttpServletResponse response) {
    this.request  = request;			
    this.response = response;			
    }
			
public void handle(Callback[] callbacks) 
    throws IOException, UnsupportedCallbackException {
      NameCallback nc = null;
     PrintWriter rw = response.getWriter();
     rw.println(callbacks.length + "Zeilen. <br>");
    for (int i=0;i<callbacks.length;i++) {
        rw.println( i + ":" + callbacks<i>.getClass().getName()+"<br>");
        }
		  
	    
  for (int i = 0; i < callbacks.length; i++) {
// Müssen Reflection benutzen, denn die folgende Klasse ist leider unerreichbar
// com.sap.engine.lib.security.http.HttpGetterCallback
     String getName = null;
     Object retVal;
     try {
        retVal = callbacks<i>.getClass().getMethod("getName",null).invoke(callbacks<i>, null );
        getName = (String) retVal ;
        rw.println( getName + "<br>");
        } catch ( Throwable e) {
            e.printStackTrace( response.getWriter() );
          }
      }
}