Author: mposolda
Date: 2011-11-03 16:50:53 -0400 (Thu, 03 Nov 2011)
New Revision: 7960
Added:
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/GateInNegotiationAuthenticator.java
Removed:
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/login/FallbackFormJBossLoginModule.java
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/NegotiationAuthenticator.java
Modified:
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java
components/sso/trunk/pom.xml
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java
Log:
GTNPORTAL-2251 Upgrade JBoss Negotiation to 2.0.4 and upgrade code according to it.
Modified:
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java
===================================================================
---
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java 2011-11-03
14:58:32 UTC (rev 7959)
+++
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -70,7 +70,7 @@
{
String action = request.getRequestURI();
- if (action != null && action.equals("/portal/sso"))
+ if (action != null && action.equals(request.getContextPath() +
"/sso"))
{
return true;
}
Modified:
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java
===================================================================
---
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java 2011-11-03
14:58:32 UTC (rev 7959)
+++
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -36,7 +36,7 @@
import org.exoplatform.container.web.AbstractFilter;
/**
- * Filter is needed because when fallback to FORM authentication, we don't need to
redirect request to PortalLoginController to secured URI,
+ * Filter is needed because when fallback to FORM authentication, we don't need to
redirect request to /dologin, which is secured URI,
* but we need to go directly to /initiatelogin without going again through Tomcat
authenticator.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -53,24 +53,18 @@
HttpServletResponse httpResponse = (HttpServletResponse)response;
try
{
- if (isLoginControllerInProgress(httpRequest))
- {
- // first save initialURI as parameter into HTTP session. We may need it later
in authenticator
- String initialURI = httpRequest.getParameter("initialURI");
- if (initialURI != null)
- {
- httpRequest.getSession().setAttribute(ATTR_INITIAL_URI, initialURI);
- }
- // we need to redirect directly to initiatelogin without going through
secured URL.
- HttpServletResponse wrapperResponse = new
IgnoreRedirectHttpResponse(httpResponse);
- chain.doFilter(request, wrapperResponse);
- httpResponse.sendRedirect("/portal/initiatelogin");
- }
- else
+ // first save initialURI as parameter into HTTP session. We may need it later in
authenticator
+ String initialURI = httpRequest.getParameter("initialURI");
+ if (initialURI != null)
{
- chain.doFilter(request, response);
+ httpRequest.getSession().setAttribute(ATTR_INITIAL_URI, initialURI);
}
+
+ // we need to redirect directly to initiatelogin without going through secured
URL.
+ HttpServletResponse wrapperResponse = new
IgnoreRedirectHttpResponse(httpResponse);
+ chain.doFilter(request, wrapperResponse);
+ httpResponse.sendRedirect(httpRequest.getContextPath() +
"/initiatelogin");
}
catch(Throwable t)
{
@@ -82,18 +76,6 @@
{
}
- private boolean isLoginControllerInProgress(HttpServletRequest request)
- {
- String action = request.getRequestURI();
-
- if (action != null && action.equals("/portal/login"))
- {
- return true;
- }
-
- return false;
- }
-
// Ignoring calls to response.sendRedirect, which are performed from
PortalLoginController
private class IgnoreRedirectHttpResponse extends HttpServletResponseWrapper
{
Deleted:
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/login/FallbackFormJBossLoginModule.java
===================================================================
---
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/login/FallbackFormJBossLoginModule.java 2011-11-03
14:58:32 UTC (rev 7959)
+++
components/sso/trunk/agent/src/main/java/org/gatein/sso/agent/login/FallbackFormJBossLoginModule.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -1,68 +0,0 @@
-/*
- * JBoss, a division of Red Hat
- * Copyright 2011, Red Hat Middleware, LLC, and individual
- * contributors as indicated by the @authors tag. See the
- * copyright.txt in the distribution for a full listing of
- * individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-
-package org.gatein.sso.agent.login;
-
-import org.exoplatform.services.security.j2ee.JbossLoginModule;
-import org.exoplatform.services.security.jaas.JAASGroup;
-import org.exoplatform.services.security.jaas.RolePrincipal;
-import org.exoplatform.services.security.jaas.UserPrincipal;
-
-import javax.security.auth.login.LoginException;
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Set;
-
-/**
- * This login module is used for SPNEGO integration. It is workaround, which returns only
identity of user in method "commit()" and it does not return any groups.
- * It is needed because {@link org.jboss.security.negotiation.spnego.SPNEGOLoginModule}
assumes in method usernamePasswordLogin()
- * that user identity is returned as first principal, which is not the case for
JbossLoginModule. Issue is addressed in
https://issues.jboss.org/browse/SECURITY-631
- *
- * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
- */
-public class FallbackFormJBossLoginModule extends JbossLoginModule
-{
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean commit() throws LoginException
- {
- if (super.commit())
- {
- Set<Principal> principals = subject.getPrincipals();
-
- // clear existing principals from subject
- principals.clear();
-
- // add only username principal
- principals.add(new UserPrincipal(identity.getUserId()));
-
- return true;
- }
- else
- {
- return false;
- }
- }
-}
Modified: components/sso/trunk/pom.xml
===================================================================
--- components/sso/trunk/pom.xml 2011-11-03 14:58:32 UTC (rev 7959)
+++ components/sso/trunk/pom.xml 2011-11-03 20:50:53 UTC (rev 7960)
@@ -79,7 +79,7 @@
<version.servlet-api>2.5</version.servlet-api>
<!-- SPNEGO support using JBoss Negotiation -->
- <version.jboss.negotiation>2.1.0.GA</version.jboss.negotiation>
+ <version.jboss.negotiation>2.0.4.GA</version.jboss.negotiation>
</properties>
<dependencyManagement>
Added:
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/GateInNegotiationAuthenticator.java
===================================================================
---
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/GateInNegotiationAuthenticator.java
(rev 0)
+++
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/GateInNegotiationAuthenticator.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -0,0 +1,63 @@
+/*
+ * JBoss, a division of Red Hat
+ * Copyright 2011, Red Hat Middleware, LLC, and individual
+ * contributors as indicated by the @authors tag. See the
+ * copyright.txt in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.gatein.sso.spnego;
+
+import org.apache.catalina.Session;
+import org.gatein.sso.agent.filter.SPNEGOFilter;
+import org.jboss.security.negotiation.NegotiationAuthenticator;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class GateInNegotiationAuthenticator extends NegotiationAuthenticator
+{
+
+ /**
+ * Return the request URI (with the corresponding query string, if any)
+ * from the saved request so that we can redirect to it. We need to override this
method
+ * because {@link org.apache.catalina.authenticator.Constants#FORM_REQUEST_NOTE} can
be null sometimes
+ * (For example when request was send to /portal/login without displaying login.jsp
page)
+ *
+ * @param session Our current session
+ */
+ @Override
+ protected String savedRequestURL(Session session)
+ {
+ String savedURI = super.savedRequestURL(session);
+
+ // use url saved by SPNEGOFilter if saved request not found
+ if (savedURI == null)
+ {
+ savedURI =
(String)session.getSession().getAttribute(SPNEGOFilter.ATTR_INITIAL_URI);
+ }
+
+ // using default context if nothing else found
+ if (savedURI == null)
+ {
+ savedURI = session.getSession().getServletContext().getContextPath();
+ }
+
+ return savedURI;
+ }
+}
Deleted:
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/NegotiationAuthenticator.java
===================================================================
---
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/NegotiationAuthenticator.java 2011-11-03
14:58:32 UTC (rev 7959)
+++
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/NegotiationAuthenticator.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -1,365 +0,0 @@
-/*
- * JBoss, a division of Red Hat
- * Copyright 2011, Red Hat Middleware, LLC, and individual
- * contributors as indicated by the @authors tag. See the
- * copyright.txt in the distribution for a full listing of
- * individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-
-package org.gatein.sso.spnego;
-
-import org.apache.catalina.Realm;
-import org.apache.catalina.Session;
-import org.apache.catalina.authenticator.AuthenticatorBase;
-import org.apache.catalina.authenticator.Constants;
-import org.apache.catalina.authenticator.FormAuthenticator;
-import org.apache.catalina.authenticator.SavedRequest;
-import org.apache.catalina.connector.Request;
-import org.apache.catalina.connector.Response;
-import org.apache.catalina.deploy.LoginConfig;
-import org.apache.log4j.Logger;
-import org.gatein.sso.agent.filter.SPNEGOFilter;
-import org.jboss.security.negotiation.MessageFactory;
-import org.jboss.security.negotiation.NegotiationException;
-import org.jboss.security.negotiation.NegotiationMessage;
-import org.jboss.security.negotiation.common.MessageTrace;
-import org.jboss.security.negotiation.common.NegotiationContext;
-import org.jboss.util.Base64;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.security.Principal;
-
-import static org.apache.catalina.authenticator.Constants.SESS_PASSWORD_NOTE;
-import static org.apache.catalina.authenticator.Constants.SESS_USERNAME_NOTE;
-import static org.apache.catalina.authenticator.Constants.FORM_ACTION;
-import static org.apache.catalina.authenticator.Constants.FORM_PASSWORD;
-import static org.apache.catalina.authenticator.Constants.FORM_PRINCIPAL_NOTE;
-import static org.apache.catalina.authenticator.Constants.FORM_USERNAME;
-
-/**
- * An authenticator to manage Negotiation based authentication in connection with the
- * Negotiation login module. It's fork of {@link
org.jboss.security.negotiation.NegotiationAuthenticator}, which is here
- * to ensure backwards compatibility with JBoss 5 (jbossWeb 2)
- *
- * @author darran.lofthouse(a)jboss.com
- * @version $Revision: 110643 $
- */
-public class NegotiationAuthenticator extends FormAuthenticator
-{
-
- private static final Logger log = Logger.getLogger(NegotiationAuthenticator.class);
-
- private static final String NEGOTIATE = "Negotiate";
-
- private static final String NEGOTIATION_CONTEXT = "NEGOTIATION_CONTEXT";
-
- private static final String FORM_METHOD = "FORM";
-
- protected String getNegotiateScheme()
- {
- return NEGOTIATE;
- }
-
- @Override
- public boolean authenticate(final Request request, final HttpServletResponse response,
final LoginConfig config)
- throws IOException
- {
-
- boolean DEBUG = log.isDebugEnabled();
- log.trace("Authenticating user");
-
- Principal principal = request.getUserPrincipal();
- if (principal != null)
- {
- if (log.isTraceEnabled())
- log.trace("Already authenticated '" + principal.getName() +
"'");
- return true;
- }
-
- String contextPath = request.getContextPath();
- String requestURI = request.getDecodedRequestURI();
- boolean loginAction = requestURI.startsWith(contextPath) &&
requestURI.endsWith(FORM_ACTION);
- if (loginAction)
- {
- Realm realm = context.getRealm();
- String username = request.getParameter(FORM_USERNAME);
- String password = request.getParameter(FORM_PASSWORD);
- principal = realm.authenticate(username, password);
- if (principal == null)
- {
- RequestDispatcher disp =
context.getServletContext().getRequestDispatcher(config.getErrorPage());
- try
- {
- disp.forward(request.getRequest(), response);
- }
- catch (ServletException e)
- {
- IOException ex = new IOException("Unable to forward to error
page.");
- ex.initCause(e);
-
- throw ex;
- }
- return false;
- }
-
- Session session = request.getSessionInternal();
- requestURI = savedRequestURL(session);
-
- session.setNote(FORM_PRINCIPAL_NOTE, principal);
- session.setNote(SESS_USERNAME_NOTE, username);
- session.setNote(SESS_PASSWORD_NOTE, password);
-
- register(request, response, principal, FORM_METHOD, username, password);
- response.sendRedirect(response.encodeRedirectURL(requestURI));
-
- return false;
- }
-
- String negotiateScheme = getNegotiateScheme();
-
- if (DEBUG)
- log.debug("Header - " +
request.getHeader("Authorization"));
- String authHeader = request.getHeader("Authorization");
- if (authHeader == null)
- {
-
- log.debug("No Authorization Header, initiating negotiation");
- initiateNegotiation(request, response, config);
-
- return false;
- }
- else if (authHeader.startsWith(negotiateScheme + " ") == false)
- {
- throw new IOException("Invalid 'Authorization' header.");
- }
-
- String authTokenBase64 = authHeader.substring(negotiateScheme.length() + 1);
- byte[] authToken = Base64.decode(authTokenBase64);
- ByteArrayInputStream authTokenIS = new ByteArrayInputStream(authToken);
- MessageTrace.logRequestBase64(authTokenBase64);
- MessageTrace.logRequestHex(authToken);
-
- Session session = request.getSessionInternal();
- NegotiationContext negotiationContext = (NegotiationContext)
session.getNote(NEGOTIATION_CONTEXT);
- if (negotiationContext == null)
- {
- log.debug("Creating new NegotiationContext");
- negotiationContext = new NegotiationContext();
- session.setNote(NEGOTIATION_CONTEXT, negotiationContext);
- }
-
- String username = negotiationContext.getUsername();
- if (username == null || username.length() == 0)
- {
- username = session.getId() + "_" +
String.valueOf(System.currentTimeMillis());
- negotiationContext.setUsername(username);
- }
- String authenticationMethod = "";
- try
- {
- // Set the ThreadLocal association.
- negotiationContext.associate();
-
- MessageFactory mf = MessageFactory.newInstance();
- if (mf.accepts(authTokenIS) == false)
- {
- throw new IOException("Unsupported negotiation mechanism.");
- }
-
- NegotiationMessage requestMessage = mf.createMessage(authTokenIS);
- negotiationContext.setRequestMessage(requestMessage);
-
- Realm realm = context.getRealm();
- principal = realm.authenticate(username, (String) null);
-
- authenticationMethod = negotiationContext.getAuthenticationMethod();
-
- if (DEBUG && principal != null)
- log.debug("authenticated principal = " + principal);
-
- NegotiationMessage responseMessage = negotiationContext.getResponseMessage();
- if (responseMessage != null)
- {
- ByteArrayOutputStream responseMessageOS = new ByteArrayOutputStream();
- responseMessage.writeTo(responseMessageOS, true);
- String responseHeader = responseMessageOS.toString();
-
- MessageTrace.logResponseBase64(responseHeader);
-
- response.setHeader("WWW-Authenticate", negotiateScheme + "
" + responseHeader);
- }
-
- }
- catch (NegotiationException e)
- {
- IOException ioe = new IOException("Error processing " +
negotiateScheme + " header.");
- ioe.initCause(e);
- throw ioe;
- }
- finally
- {
- // Clear the headers and remove the ThreadLocal association.
- negotiationContext.clear();
- }
-
- if (principal == null)
- {
- response.sendError(Response.SC_UNAUTHORIZED);
- }
- else
- {
- register(request, response, principal, authenticationMethod, username, null);
- }
-
- return (principal != null);
- }
-
- /**
- * Purpose of this method is backwards compatibility with JBoss 5.1
- *
- * @param request request
- * @param response response
- * @param config login configuration
- * @return result of authentication
- * @throws IOException
- */
- public boolean authenticate(final Request request, final Response response, final
LoginConfig config)
- throws IOException
- {
- return authenticate(request, (HttpServletResponse)response, config);
- }
-
- /**
- * Purpose of this method is backwards compatibility with JBoss 5.1
- *
- * @param request request
- * @param response response
- * @param principal Principal to register
- * @param authType authentication type (FORM, BASIC, SPNEGO, ...)
- * @param username name of user
- * @param password password of user
- *
- */
- protected void register(Request request, HttpServletResponse response,
- Principal principal, String authType,
- String username, String password)
- {
- try
- {
- // first trying JBoss 6 signature register(Request, HttpServletResponse,
Principal, String, String, String)
- Method registerNewSignature =
AuthenticatorBase.class.getDeclaredMethod("register", Request.class,
HttpServletResponse.class, Principal.class, String.class, String.class, String.class);
-
- // We have a method, so calling super
- if (registerNewSignature != null)
- {
- super.register(request, response, principal, authType, username, password);
- }
- }
- catch (NoSuchMethodException nsme)
- {
- // fallback to JBoss 5 signature register(Request, Response, Principal, String,
String, String)
- if (log.isDebugEnabled())
- {
- log.debug("Method 'register' with signature register(Request,
HttpServletResponse, Principal, String, String, String) not found. Fallback to JBoss 5
signature register(Request, Response, Principal, String, String, String).");
- }
- try
- {
- Method registerOldSignature =
AuthenticatorBase.class.getDeclaredMethod("register", Request.class,
Response.class, Principal.class, String.class, String.class, String.class);
- registerOldSignature.invoke(this, request, (Response)response, principal,
authType, username, password);
- }
- catch (Exception e)
- {
- log.error(e);
- }
- }
- catch (Exception e)
- {
- log.error(e);
- }
- }
-
- /**
- * Return the request URI (with the corresponding query string, if any)
- * from the saved request so that we can redirect to it. We need to override this
method
- * because Constants.FORM_REQUEST_NOTE can be null sometimes (when request was send
to /portal/login without displaying login.jsp page)
- *
- * @param session Our current session
- */
- protected String savedRequestURL(Session session)
- {
- String savedURI = super.savedRequestURL(session);
-
- // use url saved by SPNEGOFilter if saved request not found
- if (savedURI == null)
- {
- savedURI =
(String)session.getSession().getAttribute(SPNEGOFilter.ATTR_INITIAL_URI);
- }
-
- // using default context if nothing helped
- if (savedURI == null)
- {
- savedURI = session.getSession().getServletContext().getContextPath();
- }
-
- return savedURI;
- }
-
- private void initiateNegotiation(final Request request, final HttpServletResponse
response, final LoginConfig config)
- throws IOException
- {
- String loginPage = config.getLoginPage();
- if (loginPage != null)
- {
- // TODO - Logic to cache and restore request.
- ServletContext servletContext = context.getServletContext();
- RequestDispatcher disp = servletContext.getRequestDispatcher(loginPage);
-
- try
- {
- Session session = request.getSessionInternal();
- saveRequest(request, session);
-
- disp.include(request.getRequest(), response);
- response.setHeader("WWW-Authenticate", getNegotiateScheme());
- response.setStatus(Response.SC_UNAUTHORIZED);
- }
- catch (ServletException e)
- {
- IOException ex = new IOException("Unable to include loginPage");
- ex.initCause(e);
-
- throw ex;
- }
-
- }
- else
- {
- response.setHeader("WWW-Authenticate", getNegotiateScheme());
- response.sendError(Response.SC_UNAUTHORIZED);
- }
-
- response.flushBuffer();
- }
-}
Modified:
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java
===================================================================
---
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java 2011-11-03
14:58:32 UTC (rev 7959)
+++
components/sso/trunk/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java 2011-11-03
20:50:53 UTC (rev 7960)
@@ -1,9 +1,9 @@
/*
- * JBoss, Home of Professional Open Source.
- *
- * Copyright 2007, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * JBoss, a division of Red Hat
+ * Copyright 2011, Red Hat Middleware, LLC, and individual
+ * contributors as indicated by the @authors tag. See the
+ * copyright.txt in the distribution for a full listing of
+ * individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -20,348 +20,43 @@
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
*/
+
package org.gatein.sso.spnego;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.acl.Group;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import org.exoplatform.services.security.jaas.UserPrincipal;
import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
+import java.security.Principal;
+import java.util.Set;
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSCredential;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.Oid;
-import org.jboss.security.SimpleGroup;
-import org.jboss.security.auth.spi.AbstractServerLoginModule;
-import org.jboss.security.negotiation.NegotiationMessage;
-import org.jboss.security.negotiation.common.NegotiationContext;
-import org.jboss.security.negotiation.spnego.encoding.NegTokenInit;
-import org.jboss.security.negotiation.spnego.encoding.NegTokenTarg;
-import org.jboss.security.negotiation.spnego.encoding.SPNEGOMessage;
-
-import org.exoplatform.services.security.jaas.UserPrincipal;
-
/**
- * Login module to work in conjunction with SPNEGOAuthenticator to handle the
- * authentication requirements.
- *
- * @author darran.lofthouse(a)jboss.com
- * @version $Revision: 83572 $
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
-public class SPNEGOLoginModule extends AbstractServerLoginModule
+public class SPNEGOLoginModule extends
org.jboss.security.negotiation.spnego.SPNEGOLoginModule
{
+ /**
+ * Obtaining identity from subject. We need to find instance of {@link UserPrincipal}
+ * , which is added here during FORM authentication.
+ * See {@link org.exoplatform.services.security.j2ee.JbossLoginModule#commit()}
+ *
+ * @param userSubject subject from FORM authentication
+ * @return identity
+ * @throws javax.security.auth.login.LoginException
+ */
+ protected Principal getIdentityFromSubject(Subject userSubject) throws LoginException
+ {
+ Set principals = userSubject.getPrincipals(UserPrincipal.class);
+ if (principals.isEmpty())
+ {
+ throw new LoginException("No UserPrincipals returned after login.");
+ }
+ else if (principals.size() > 1)
+ {
+ log.warn("Multiple UserPrincipals returned, using first principal in
set.");
+ }
- private static final String SPNEGO = "SPNEGO";
-
- private static final Oid kerberos;
-
- // TODO - Pick a name for a default domain?
- private String serverSecurityDomain;
-
- private LoginContext serverLoginContext = null;
-
- private Principal identity = null;
-
-
- static
- {
- try
- {
- kerberos = new Oid("1.2.840.113554.1.2.2");
- }
- catch (GSSException e)
- {
- throw new RuntimeException("Unable to initialise Oid", e);
- }
- }
-
- @Override
- public void initialize(final Subject subject,
- final CallbackHandler callbackHandler, final Map sharedState,
- final Map options)
- {
- super.initialize(subject, callbackHandler, sharedState, options);
-
- // Which security domain to authenticate the server.
- serverSecurityDomain = (String) options.get("serverSecurityDomain");
- log.debug("serverSecurityDomain=" + serverSecurityDomain);
- }
-
- @Override
- public boolean login() throws LoginException
- {
- if (super.login() == true)
- {
- log.debug("super.login()==true");
- return true;
- }
-
- super.loginOk = false;
-
- NegotiationContext negotiationContext = NegotiationContext
- .getCurrentNegotiationContext();
- NegotiationMessage requestMessage = negotiationContext.getRequestMessage();
- if (requestMessage instanceof SPNEGOMessage == false)
- {
- String message = "Unsupported negotiation mechanism '"
- + requestMessage.getMessageType() + "'.";
- log.warn(message);
- throw new LoginException(message);
- }
-
- try
- {
- Subject server = getServerSubject();
- AcceptSecContext action = new AcceptSecContext(negotiationContext);
- Object result = Subject.doAs(server, action);
-
- log.trace("Result - " + result);
-
- if (result instanceof Boolean)
- {
- if (Boolean.TRUE.equals(result))
- {
- super.loginOk = true;
- if (getUseFirstPass() == true)
- {
- String userName = identity.getName();
- log.debug("Storing username '" + userName + "' and empty
password");
- // Add the username and a null password to the shared state map
- sharedState.put("javax.security.auth.login.name", identity);
- sharedState.put("javax.security.auth.login.password", "");
- }
- }
- }
- else if (result instanceof Exception)
- {
- Exception e = (Exception) result;
- log.error("Unable to authenticate", e);
- throw new LoginException("Unable to authenticate - " + e.getMessage());
- }
-
- }
- finally
- {
- if (serverLoginContext != null)
- {
- // TODO - We may not actually want to logout as if we use cache this may
- // clear it,
- serverLoginContext.logout();
- }
- }
-
- log.trace("super.loginOk " + super.loginOk);
- if (super.loginOk == true)
- {
- return true;
- }
- else
- {
- throw new LoginException("Continuation Required.");
- }
-
- }
-
- @Override
- protected Principal getIdentity()
- {
- return identity;
- }
-
- @Override
- protected Group[] getRoleSets() throws LoginException
- {
- Group roles = new SimpleGroup("Roles");
- Group callerPrincipal = new SimpleGroup("CallerPrincipal");
- Group[] groups = { roles, callerPrincipal };
- callerPrincipal.addMember(getIdentity());
- return groups;
- }
-
- protected Subject getServerSubject() throws LoginException
- {
- LoginContext lc = new LoginContext(serverSecurityDomain);
- lc.login();
- // Cache so we can log out.
- serverLoginContext = lc;
-
- Subject serverSubject = serverLoginContext.getSubject();
- log.debug("Subject = " + serverSubject);
- log.debug("Logged in '" + serverSecurityDomain + "'
LoginContext");
-
- return serverSubject;
- }
-
- private class AcceptSecContext implements PrivilegedAction
- {
-
- private final NegotiationContext negotiationContext;
-
- public AcceptSecContext(final NegotiationContext negotiationContext)
- {
- this.negotiationContext = negotiationContext;
- }
-
- public Object run()
- {
- try
- {
- // The message type will have already been checked before this point so
- // we know it is
- // a SPNEGO message.
- NegotiationMessage requestMessage = negotiationContext
- .getRequestMessage();
-
- // TODO - Ensure no way to fall through with gssToken still null.
- byte[] gssToken = null;
- if (requestMessage instanceof NegTokenInit)
- {
- NegTokenInit negTokenInit = (NegTokenInit) requestMessage;
- List<Oid> mechList = negTokenInit.getMechTypes();
-
- if (mechList.get(0).equals(kerberos))
- {
- gssToken = negTokenInit.getMechToken();
- }
- else
- {
- boolean kerberosSupported = false;
-
- Iterator<Oid> it = mechList.iterator();
- while (it.hasNext() && kerberosSupported == false)
- {
- kerberosSupported = it.next().equals(kerberos);
- }
-
- NegTokenTarg negTokenTarg = new NegTokenTarg();
-
- if (kerberosSupported)
- {
- negTokenTarg.setNegResult(NegTokenTarg.ACCEPT_INCOMPLETE);
- negTokenTarg.setSupportedMech(kerberos);
- }
- else
- {
- negTokenTarg.setNegResult(NegTokenTarg.REJECTED);
- }
- negotiationContext.setResponseMessage(negTokenTarg);
-
- return Boolean.FALSE;
- }
-
- }
- else if (requestMessage instanceof NegTokenTarg)
- {
- NegTokenTarg negTokenTarg = (NegTokenTarg) requestMessage;
-
- gssToken = negTokenTarg.getResponseToken();
- }
-
- Object schemeContext = negotiationContext.getSchemeContext();
- if (schemeContext != null
- && schemeContext instanceof GSSContext == false)
- {
- throw new IllegalStateException(
- "The schemeContext is not a GSSContext");
- }
-
- GSSContext gssContext = (GSSContext) schemeContext;
- if (gssContext == null)
- {
- log.debug("Creating new GSSContext.");
- GSSManager manager = GSSManager.getInstance();
- gssContext = manager.createContext((GSSCredential) null);
-
- negotiationContext.setSchemeContext(gssContext);
- }
-
- if (gssContext.isEstablished())
- {
- log
- .warn("Authentication was performed despite already being
authenticated!");
-
- // TODO - Refactor to only do this once.
- // identity = new
- // KerberosPrincipal(gssContext.getSrcName().toString());
- identity = new UserPrincipal(mapSpnegoToGateIn(gssContext
- .getSrcName().toString()));
-
- log.debug("context.getCredDelegState() = "
- + gssContext.getCredDelegState());
- log.debug("context.getMutualAuthState() = "
- + gssContext.getMutualAuthState());
- log.debug("context.getSrcName() = "
- + gssContext.getSrcName().toString());
-
- negotiationContext.setAuthenticationMethod(SPNEGO);
- negotiationContext.setAuthenticated(true);
-
- return Boolean.TRUE;
- }
-
- byte[] respToken = gssContext.acceptSecContext(gssToken, 0,
- gssToken.length);
-
- if (respToken != null)
- {
- NegTokenTarg negTokenTarg = new NegTokenTarg();
- negTokenTarg.setResponseToken(respToken);
-
- negotiationContext.setResponseMessage(negTokenTarg);
- }
-
- if (gssContext.isEstablished() == false)
- {
- return Boolean.FALSE;
- }
- else
- {
- // identity = new
- // KerberosPrincipal(gssContext.getSrcName().toString());
- identity = new UserPrincipal(mapSpnegoToGateIn(gssContext
- .getSrcName().toString()));
-
- log.debug("context.getCredDelegState() = "
- + gssContext.getCredDelegState());
- log.debug("context.getMutualAuthState() = "
- + gssContext.getMutualAuthState());
- log.debug("context.getSrcName() = "
- + gssContext.getSrcName().toString());
-
- // TODO - Get these two in synch - maybe isAuthenticated based on an
- // authentication method been set?
- negotiationContext.setAuthenticationMethod(SPNEGO);
- negotiationContext.setAuthenticated(true);
- return Boolean.TRUE;
- }
-
- }
- catch (Exception e)
- {
- return e;
- }
-
- }
- }
-
- private String mapSpnegoToGateIn(String spnegoPrincipal)
- {
- String exoPrincipal = spnegoPrincipal;
-
- int indexOf = exoPrincipal.indexOf('@');
- if (indexOf != -1)
- {
- exoPrincipal = exoPrincipal.substring(0, indexOf).trim();
- }
-
- return exoPrincipal;
- }
+ Principal identity = (Principal) principals.iterator().next();
+ return identity;
+ }
}