package org.jboss.seam.security.external.openid;
import java.io.IOException;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.seam.security.external.InvalidRequestException;
import org.jboss.seam.security.external.OpenIdRequestedAttributeImpl;
import org.jboss.seam.security.external.ResponseHandler;
import org.jboss.seam.security.external.dialogues.DialogueBean;
import org.jboss.seam.security.external.dialogues.api.DialogueManager;
import org.jboss.seam.security.external.openid.api.OpenIdRequestedAttribute;
import org.jboss.seam.security.external.spi.OpenIdProviderSpi;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.DirectError;
import org.openid4java.message.Message;
import org.openid4java.message.MessageException;
import org.openid4java.message.MessageExtension;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.openid4java.server.ServerManager;
/**
* @author Marcel Kolsteren
*
*/
public class OpenIdProviderAuthenticationService
{
@Inject
private Instance<OpenIdProviderRequest> openIdProviderRequest;
@Inject
private Instance<ServerManager> openIdServerManager;
@Inject
private Instance<OpenIdProviderSpi> openIdProviderSpi;
@Inject
private ResponseHandler responseHandler;
@Inject
private DialogueManager dialogueManager;
@Inject
private Instance<DialogueBean> dialogue;
@Inject
private Instance<OpenIdProviderBean> opBean;
public void handleIncomingMessage(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws InvalidRequestException
{
ParameterList parameterList = new ParameterList(httpRequest.getParameterMap());
String mode = parameterList.getParameterValue("openid.mode");
Message associationResponse;
if ("associate".equals(mode))
{
associationResponse = openIdServerManager.get().associationResponse(parameterList);
writeMessageToResponse(associationResponse, httpResponse);
}
else if ("checkid_setup".equals(mode) || "checkid_immediate".equals(mode))
{
dialogueManager.beginDialogue();
String claimedIdentifier = parameterList.getParameterValue("openid.claimed_id");
String opLocalIdentifier = parameterList.getParameterValue("openid.identity");
openIdProviderRequest.get().setParameterList(parameterList);
openIdProviderRequest.get().setClaimedIdentifier(claimedIdentifier);
MessageExtension ext = null;
try
{
AuthRequest authReq = AuthRequest.createAuthRequest(parameterList, openIdServerManager.get().getRealmVerifier());
if (authReq.hasExtension(AxMessage.OPENID_NS_AX))
{
ext = authReq.getExtension(AxMessage.OPENID_NS_AX);
}
}
catch (MessageException e)
{
throw new RuntimeException(e);
}
if (ext instanceof FetchRequest)
{
FetchRequest fetchRequest = (FetchRequest) ext;
List<OpenIdRequestedAttribute> requestedAttributes = new LinkedList<OpenIdRequestedAttribute>();
handleAttributeRequests(fetchRequest, requestedAttributes, false);
handleAttributeRequests(fetchRequest, requestedAttributes, true);
openIdProviderRequest.get().setRequestedAttributes(requestedAttributes);
openIdProviderRequest.get().setFetchRequest(fetchRequest);
}
if (claimedIdentifier != null && opLocalIdentifier != null)
{
boolean immediate = "checkid_immediate".equals(mode);
String realm = parameterList.getParameterValue("openid.realm");
if (realm == null)
{
realm = parameterList.getParameterValue("openid.return_to");
}
if (opLocalIdentifier.equals(AuthRequest.SELECT_ID))
{
openIdProviderSpi.get().authenticate(realm, null, immediate, responseHandler.createResponseHolder(httpResponse));
}
else
{
String userName = opBean.get().getUserNameFromOpLocalIdentifier(opLocalIdentifier);
openIdProviderSpi.get().authenticate(realm, userName, immediate, responseHandler.createResponseHolder(httpResponse));
}
}
else
{
associationResponse = DirectError.createDirectError("Invalid request; claimed_id or identity attribute is missing");
writeMessageToResponse(associationResponse, httpResponse);
}
dialogueManager.detachDialogue();
}
else if ("check_authentication".equals(mode))
{
associationResponse = openIdServerManager.get().verify(parameterList);
writeMessageToResponse(associationResponse, httpResponse);
}
else
{
associationResponse = DirectError.createDirectError("Unknown request");
writeMessageToResponse(associationResponse, httpResponse);
}
}
private void handleAttributeRequests(FetchRequest fetchRequest, List<OpenIdRequestedAttribute> requestedAttributes, boolean required)
{
@SuppressWarnings("unchecked")
Map<String, String> attributes = fetchRequest.getAttributes(required);
for (Map.Entry<String, String> entry : attributes.entrySet())
{
OpenIdRequestedAttributeImpl requestedAttribute = new OpenIdRequestedAttributeImpl();
requestedAttribute.setAlias(entry.getKey());
requestedAttribute.setTypeUri(entry.getValue());
requestedAttribute.setRequired(required);
requestedAttribute.setCount(fetchRequest.getCount(entry.getKey()));
requestedAttributes.add(requestedAttribute);
}
}
public void sendAuthenticationResponse(boolean authenticationSuccesful, Map<String, List<String>> attributeValues, HttpServletResponse response)
{
ParameterList parameterList = openIdProviderRequest.get().getParameterList();
String userName = openIdProviderRequest.get().getUserName();
String opLocalIdentifier = opBean.get().getOpLocalIdentifierForUserName(userName);
String claimedIdentifier = openIdProviderRequest.get().getClaimedIdentifier();
if (claimedIdentifier.equals(AuthRequest.SELECT_ID))
{
claimedIdentifier = opLocalIdentifier;
}
Message authResponse = openIdServerManager.get().authResponse(parameterList, opLocalIdentifier, claimedIdentifier, authenticationSuccesful);
if (response instanceof DirectError)
{
writeMessageToResponse(authResponse, response);
}
else
{
if (openIdProviderRequest.get().getRequestedAttributes() != null)
{
try
{
FetchResponse fetchResponse = FetchResponse.createFetchResponse(openIdProviderRequest.get().getFetchRequest(), attributeValues);
authResponse.addExtension(fetchResponse);
}
catch (MessageException e)
{
throw new RuntimeException(e);
}
}
// caller will need to decide which of the following to use:
// option1: GET HTTP-redirect to the return_to URL
String destinationUrl = authResponse.getDestinationUrl(true);
responseHandler.sendHttpRedirectToUserAgent(destinationUrl, response);
// option2: HTML FORM Redirection
// RequestDispatcher dispatcher =
// getServletContext().getRequestDispatcher("formredirection.jsp");
// httpReq.setAttribute("prameterMap", response.getParameterMap());
// httpReq.setAttribute("destinationUrl",
// response.getDestinationUrl(false));
// dispatcher.forward(request, response);
// return null;
}
dialogue.get().setFinished(true);
}
private void writeMessageToResponse(Message message, HttpServletResponse response)
{
Writer writer = responseHandler.getWriter("text/plain", response);
try
{
writer.append(message.keyValueFormEncoding());
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
}