Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jetty-security/src/main/java/org')
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/Authentication.java66
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java53
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java28
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java79
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java316
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java31
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthentication.java59
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java88
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java119
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/DefaultUserIdentity.java71
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java90
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java247
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java99
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java263
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/LazyAuthentication.java85
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java28
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java292
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java135
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/RoleRunAsToken.java39
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/RunAsToken.java22
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java524
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/ServerAuthException.java42
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/UserDataConstraint.java35
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java106
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java98
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DelegateAuthenticator.java57
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java333
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java219
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LazyAuthenticator.java45
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java44
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallback.java50
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java104
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionCachingAuthenticator.java59
-rw-r--r--jetty-security/src/main/java/org/eclipse/jetty/security/authentication/XCPSCachingAuthenticator.java55
34 files changed, 3981 insertions, 0 deletions
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/Authentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/Authentication.java
new file mode 100644
index 0000000000..51dd8ce815
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/Authentication.java
@@ -0,0 +1,66 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+/**
+ * Authentication state of a user.
+ *
+ * @version $Rev: 4701 $ $Date: 2009-03-03 13:01:26 +0100 (Tue, 03 Mar 2009) $
+ */
+public interface Authentication
+{
+ public enum Status
+ {
+ SEND_FAILURE(false), SEND_SUCCESS(true), SEND_CONTINUE(false), SUCCESS(true);
+ boolean _success;
+ Status(boolean success) {_success=success; }
+ public boolean isSuccess(){ return _success;}
+ }
+
+ Status getAuthStatus();
+
+ String getAuthMethod();
+
+ UserIdentity getUserIdentity();
+
+ boolean isSuccess();
+
+
+ public static final Authentication SUCCESS_UNAUTH_RESULTS = new Authentication()
+ {
+ public String getAuthMethod() {return null;}
+ public Status getAuthStatus() {return Authentication.Status.SUCCESS;}
+ public UserIdentity getUserIdentity() {return UserIdentity.UNAUTHENTICATED_IDENTITY;}
+ public boolean isSuccess() {return true;}
+ };
+
+ public static final Authentication SEND_CONTINUE_RESULTS = new Authentication()
+ {
+ public String getAuthMethod() {return null;}
+ public Status getAuthStatus() {return Authentication.Status.SEND_CONTINUE;}
+ public UserIdentity getUserIdentity() {return UserIdentity.UNAUTHENTICATED_IDENTITY;}
+ public boolean isSuccess() {return false;}
+ };
+
+ public static final Authentication SEND_FAILURE_RESULTS = new Authentication()
+ {
+ public String getAuthMethod() {return null;}
+ public Status getAuthStatus() {return Authentication.Status.SEND_FAILURE;}
+ public UserIdentity getUserIdentity() {return UserIdentity.UNAUTHENTICATED_IDENTITY;}
+ public boolean isSuccess() {return false;}
+ };
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java
new file mode 100644
index 0000000000..f3e37aa697
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java
@@ -0,0 +1,53 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.server.Server;
+
+/**
+ * This is like the JASPI ServerAuthContext but is intended to be easier to use
+ * and allow lazy auth.
+ *
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public interface Authenticator
+{
+ void setConfiguration(Configuration configuration);
+ String getAuthMethod();
+
+ Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException;
+ Authentication.Status secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, Authentication validatedUser) throws ServerAuthException;
+
+ interface Configuration
+ {
+ String getAuthMethod();
+ String getRealmName();
+ boolean isLazy();
+ String getInitParameter(String key);
+ Set<String> getInitParameterNames();
+ LoginService getLoginService();
+ IdentityService getIdentityService();
+ }
+
+ interface Factory
+ {
+ Authenticator getAuthenticator(Server server, ServletContext context, Configuration configuration);
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java
new file mode 100644
index 0000000000..1135aa7591
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java
@@ -0,0 +1,28 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.util.Set;
+
+/**
+ * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ */
+public interface ConstraintAware
+{
+ ConstraintMapping[] getConstraintMappings();
+
+ Set<String> getRoles();
+
+ void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles);
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java
new file mode 100644
index 0000000000..378ff14d57
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java
@@ -0,0 +1,79 @@
+// ========================================================================
+// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import org.eclipse.jetty.http.security.Constraint;
+
+public class ConstraintMapping
+{
+ String _method;
+
+ String _pathSpec;
+
+ Constraint _constraint;
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the constraint.
+ */
+ public Constraint getConstraint()
+ {
+ return _constraint;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param constraint The constraint to set.
+ */
+ public void setConstraint(Constraint constraint)
+ {
+ this._constraint = constraint;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the method.
+ */
+ public String getMethod()
+ {
+ return _method;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param method The method to set.
+ */
+ public void setMethod(String method)
+ {
+ this._method = method;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the pathSpec.
+ */
+ public String getPathSpec()
+ {
+ return _pathSpec;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param pathSpec The pathSpec to set.
+ */
+ public void setPathSpec(String pathSpec)
+ {
+ this._pathSpec = pathSpec;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
new file mode 100644
index 0000000000..361e45e441
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
@@ -0,0 +1,316 @@
+// ========================================================================
+// Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jetty.http.PathMap;
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.StringMap;
+
+/* ------------------------------------------------------------ */
+/**
+ * Handler to enforce SecurityConstraints. This implementation is servlet spec
+ * 2.4 compliant and precomputes the constraint combinations for runtime
+ * efficiency.
+ *
+ */
+public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
+{
+ private ConstraintMapping[] _constraintMappings;
+ private Set<String> _roles;
+ private PathMap _constraintMap = new PathMap();
+ private boolean _strict = true;
+
+
+ /* ------------------------------------------------------------ */
+ /** Get the strict mode.
+ * @return true if the security handler is running in strict mode.
+ */
+ public boolean isStrict()
+ {
+ return _strict;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the strict mode of the security handler.
+ * <p>
+ * When in strict mode (the default), the full servlet specification
+ * will be implemented.
+ * If not in strict mode, some additional flexibility in configuration
+ * is allowed:<ul>
+ * <li>All users do not need to have a role defined in the deployment descriptor
+ * <li>The * role in a constraint applies to ANY role rather than all roles defined in
+ * the deployment descriptor.
+ * </ul>
+ *
+ * @param strict the strict to set
+ */
+ public void setStrict(boolean strict)
+ {
+ _strict = strict;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Returns the contraintMappings.
+ */
+ public ConstraintMapping[] getConstraintMappings()
+ {
+ return _constraintMappings;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Set<String> getRoles()
+ {
+ return _roles;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Process the constraints following the combining rules in Servlet 3.0 EA
+ * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
+ *
+ * @param constraintMappings
+ * The contraintMappings to set.
+ * @param roles
+ */
+ public void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles)
+ {
+ if (isStarted())
+ throw new IllegalStateException("Started");
+ _constraintMappings = constraintMappings;
+ this._roles = roles;
+
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.SecurityHandler#doStart()
+ */
+ @Override
+ protected void doStart() throws Exception
+ {
+ _constraintMap.clear();
+ if (_constraintMappings != null)
+ {
+ for (ConstraintMapping mapping : _constraintMappings)
+ {
+ Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
+ if (mappings == null)
+ {
+ mappings = new StringMap();
+ _constraintMap.put(mapping.getPathSpec(),mappings);
+ }
+ RoleInfo allMethodsRoleInfo = mappings.get(null);
+ if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
+ {
+ continue;
+ }
+ String httpMethod = mapping.getMethod();
+ RoleInfo roleInfo = mappings.get(httpMethod);
+ if (roleInfo == null)
+ {
+ roleInfo = new RoleInfo();
+ mappings.put(httpMethod,roleInfo);
+ if (allMethodsRoleInfo != null)
+ {
+ roleInfo.combine(allMethodsRoleInfo);
+ }
+ }
+ if (roleInfo.isForbidden())
+ {
+ continue;
+ }
+ Constraint constraint = mapping.getConstraint();
+ boolean forbidden = constraint.isForbidden();
+ roleInfo.setForbidden(forbidden);
+ if (forbidden)
+ {
+ if (httpMethod == null)
+ {
+ mappings.clear();
+ mappings.put(null,roleInfo);
+ }
+ }
+ else
+ {
+ UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint());
+ roleInfo.setUserDataConstraint(userDataConstraint);
+
+ boolean unchecked = !constraint.getAuthenticate();
+ roleInfo.setUnchecked(unchecked);
+ if (!roleInfo.isUnchecked())
+ {
+ if (constraint.isAnyRole())
+ {
+ if (_strict)
+ {
+ // * means "all defined roles"
+ for (String role : _roles)
+ roleInfo.addRole(role);
+ }
+ else
+ // * means any role
+ roleInfo.setAnyRole(true);
+ }
+ else
+ {
+ String[] newRoles = constraint.getRoles();
+ for (String role : newRoles)
+ {
+ if (_strict &&!_roles.contains(role))
+ throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
+ roleInfo.addRole(role);
+ }
+ }
+ }
+ if (httpMethod == null)
+ {
+ for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
+ {
+ if (entry.getKey() != null)
+ {
+ RoleInfo specific = entry.getValue();
+ specific.combine(roleInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+ super.doStart();
+ }
+
+ protected Object prepareConstraintInfo(String pathInContext, Request request)
+ {
+ Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
+
+ if (mappings != null)
+ {
+ String httpMethod = request.getMethod();
+ RoleInfo roleInfo = mappings.get(httpMethod);
+ if (roleInfo == null)
+ {
+ roleInfo = mappings.get(null);
+ if (roleInfo != null)
+ {
+ return roleInfo;
+ }
+ }
+ }
+ return null;
+ }
+
+ protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
+ {
+ if (constraintInfo == null)
+ {
+ return true;
+ }
+ RoleInfo roleInfo = (RoleInfo)constraintInfo;
+ if (roleInfo.isForbidden())
+ {
+ return false;
+ }
+ UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint();
+ if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
+ {
+ return true;
+ }
+ HttpConnection connection = HttpConnection.getCurrentConnection();
+ Connector connector = connection.getConnector();
+
+ if (dataConstraint == UserDataConstraint.Integral)
+ {
+ if (connector.isIntegral(request))
+ return true;
+ if (connector.getConfidentialPort() > 0)
+ {
+ String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI();
+ if (request.getQueryString() != null)
+ url += "?" + request.getQueryString();
+ response.setContentLength(0);
+ response.sendRedirect(url);
+ request.setHandled(true);
+ }
+ return false;
+ }
+ else if (dataConstraint == UserDataConstraint.Confidential)
+ {
+ if (connector.isConfidential(request))
+ return true;
+
+ if (connector.getConfidentialPort() > 0)
+ {
+ String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
+ + request.getRequestURI();
+ if (request.getQueryString() != null)
+ url += "?" + request.getQueryString();
+
+ response.setContentLength(0);
+ response.sendRedirect(url);
+ request.setHandled(true);
+ }
+ return false;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Invalid dataConstraint value: " + dataConstraint);
+ }
+
+ }
+
+ protected boolean isAuthMandatory(Request base_request, Response base_response, Object constraintInfo)
+ {
+ if (constraintInfo == null)
+ {
+ return false;
+ }
+ return !((RoleInfo)constraintInfo).isUnchecked();
+ }
+
+ protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
+ throws IOException
+ {
+ if (constraintInfo == null)
+ {
+ return true;
+ }
+ RoleInfo roleInfo = (RoleInfo)constraintInfo;
+
+ if (roleInfo.isUnchecked())
+ {
+ return true;
+ }
+
+ if (roleInfo.isAnyRole() && request.getAuthType()!=null)
+ return true;
+
+ String[] roles = roleInfo.getRoles();
+ for (String role : roles)
+ {
+ if (userIdentity.isUserInRole(role))
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
new file mode 100644
index 0000000000..9e202beb9a
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
@@ -0,0 +1,31 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ */
+public interface CrossContextPsuedoSession<T>
+{
+
+ T fetch(HttpServletRequest request);
+
+ void store(T data, HttpServletResponse response);
+
+ void clear(HttpServletRequest request);
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthentication.java
new file mode 100644
index 0000000000..58b41007d5
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthentication.java
@@ -0,0 +1,59 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class DefaultAuthentication implements Authentication
+{
+ private final Authentication.Status _authStatus;
+ private final String _authMethod;
+ private final UserIdentity _userIdentity;
+
+ public DefaultAuthentication(Authentication.Status authStatus, String authMethod, UserIdentity userIdentity)
+ {
+ _authStatus = authStatus;
+ _authMethod = authMethod;
+ _userIdentity=userIdentity;
+ }
+
+ public String getAuthMethod()
+ {
+ return _authMethod;
+ }
+
+ public Authentication.Status getAuthStatus()
+ {
+ return _authStatus;
+ }
+
+ public UserIdentity getUserIdentity()
+ {
+ return _userIdentity;
+ }
+
+ public boolean isSuccess()
+ {
+ return _authStatus.isSuccess();
+ }
+
+ public String toString()
+ {
+ return "{Auth,"+_authMethod+","+_authStatus+","+","+_userIdentity+"}";
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java
new file mode 100644
index 0000000000..75fa6ac8c8
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java
@@ -0,0 +1,88 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.security.Authenticator.Configuration;
+import org.eclipse.jetty.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.security.authentication.ClientCertAuthenticator;
+import org.eclipse.jetty.security.authentication.DigestAuthenticator;
+import org.eclipse.jetty.security.authentication.FormAuthenticator;
+import org.eclipse.jetty.security.authentication.LazyAuthenticator;
+import org.eclipse.jetty.security.authentication.SessionCachingAuthenticator;
+import org.eclipse.jetty.server.Server;
+
+/* ------------------------------------------------------------ */
+/**
+ * The Default Authenticator Factory.
+ * Uses the {@link Configuration#getAuthMethod()} to select an {@link Authenticator} from: <ul>
+ * <li>{@link BasicAuthenticator}</li>
+ * <li>{@link DigestAuthenticator}</li>
+ * <li>{@link FormAuthenticator}</li>
+ * <li>{@link ClientCertAuthenticator}</li>
+ * </ul>
+ * If {@link Configuration#isLazy()} is true, the Authenticator is wrapped with a {@link LazyAuthenticator}
+ * instance. The FormAuthenticator is always wrapped in a {@link SessionCachingAuthenticator}.
+ * <p>
+ * If a {@link LoginService} has not been set on this factory, then
+ * the service is selected by searching the {@link Server#getBeans(Class)} results for
+ * a service that matches the realm name, else the first LoginService found is used.
+ *
+ */
+public class DefaultAuthenticatorFactory implements Authenticator.Factory
+{
+ LoginService _loginService;
+
+ public Authenticator getAuthenticator(Server server, ServletContext context, Configuration configuration)
+ {
+ String auth=configuration.getAuthMethod();
+ Authenticator authenticator=null;
+
+ if (auth==null || Constraint.__BASIC_AUTH.equalsIgnoreCase(auth))
+ authenticator=new BasicAuthenticator();
+ else if (Constraint.__DIGEST_AUTH.equalsIgnoreCase(auth))
+ authenticator=new DigestAuthenticator();
+ else if (Constraint.__FORM_AUTH.equalsIgnoreCase(auth))
+ authenticator=new SessionCachingAuthenticator(new FormAuthenticator());
+ if (Constraint.__CERT_AUTH.equalsIgnoreCase(auth)||Constraint.__CERT_AUTH2.equalsIgnoreCase(auth))
+ authenticator=new ClientCertAuthenticator();
+
+ if (configuration.isLazy() && authenticator!=null)
+ authenticator=new LazyAuthenticator(authenticator);
+
+ return authenticator;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the loginService
+ */
+ public LoginService getLoginService()
+ {
+ return _loginService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param loginService the loginService to set
+ */
+ public void setLoginService(LoginService loginService)
+ {
+ _loginService = loginService;
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java
new file mode 100644
index 0000000000..ada4b36d4d
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java
@@ -0,0 +1,119 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.security.Principal;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.server.UserIdentity.Scope;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * Default Identity Service implementation.
+ * This service handles only role reference maps passed in an
+ * associated {@link UserIdentity.Scope}. If there are roles
+ * refs present, then associate will wrap the UserIdentity with one
+ * that uses the role references in the {@link UserIdentity#isUserInRole(String)}
+ * implementation. All other operations are effectively noops.
+ *
+ */
+public class DefaultIdentityService implements IdentityService<UserIdentity, RoleRunAsToken>
+{
+ public DefaultIdentityService()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * If there are roles refs present in the scope, then wrap the UserIdentity
+ * with one that uses the role references in the {@link UserIdentity#isUserInRole(String)}
+ */
+ public UserIdentity associate(UserIdentity user, Scope scope)
+ {
+ Map<String,String> roleRefMap=scope.getRoleRefMap();
+ if (roleRefMap!=null && roleRefMap.size()>0)
+ return new RoleRefUserIdentity(user,roleRefMap);
+ return user;
+ }
+
+ public void disassociate(UserIdentity scoped)
+ {
+ }
+
+ public RoleRunAsToken associateRunAs(RunAsToken token)
+ {
+ return null;
+ }
+
+ public void disassociateRunAs(RoleRunAsToken lastToken)
+ {
+ }
+
+ public RunAsToken newRunAsToken(String runAsName)
+ {
+ return new RoleRunAsToken(runAsName);
+ }
+
+ public UserIdentity newSystemUserIdentity()
+ {
+ return null;
+ }
+
+ public UserIdentity newUserIdentity(final Subject subject, final Principal userPrincipal, final String[] roles)
+ {
+ return new DefaultUserIdentity(subject,userPrincipal,roles);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Wrapper UserIdentity used to apply RoleRef map.
+ *
+ */
+ public static class RoleRefUserIdentity implements UserIdentity
+ {
+ final private UserIdentity _delegate;
+ final private Map<String,String> _roleRefMap;
+
+ public RoleRefUserIdentity(final UserIdentity user, final Map<String, String> roleRefMap)
+ {
+ _delegate=user;
+ _roleRefMap=roleRefMap;
+ }
+
+ public String[] getRoles()
+ {
+ return _delegate.getRoles();
+ }
+
+ public Subject getSubject()
+ {
+ return _delegate.getSubject();
+ }
+
+ public Principal getUserPrincipal()
+ {
+ return _delegate.getUserPrincipal();
+ }
+
+ public boolean isUserInRole(String role)
+ {
+ String link=_roleRefMap.get(role);
+ return _delegate.isUserInRole(link==null?role:link);
+ }
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultUserIdentity.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultUserIdentity.java
new file mode 100644
index 0000000000..07580f00e3
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultUserIdentity.java
@@ -0,0 +1,71 @@
+// ========================================================================
+// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.security.Authentication.Status;
+import org.eclipse.jetty.server.UserIdentity;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * The default implementation of UserIdentity.
+ *
+ */
+public class DefaultUserIdentity implements UserIdentity
+{
+ /* Cache successful authentications for BASIC and DIGEST to avoid creation on every request */
+ public final Authentication SUCCESSFUL_BASIC = new DefaultAuthentication(Status.SUCCESS,Constraint.__BASIC_AUTH,this);
+ public final Authentication SUCCESSFUL_DIGEST = new DefaultAuthentication(Status.SUCCESS,Constraint.__BASIC_AUTH,this);
+
+ private final Subject _subject;
+ private final Principal _userPrincipal;
+ private final String[] _roles;
+
+ public DefaultUserIdentity(Subject subject, Principal userPrincipal, String[] roles)
+ {
+ _subject=subject;
+ _userPrincipal=userPrincipal;
+ _roles=roles;
+ }
+
+ public String[] getRoles()
+ {
+ return _roles;
+ }
+
+ public Subject getSubject()
+ {
+ return _subject;
+ }
+
+ public Principal getUserPrincipal()
+ {
+ return _userPrincipal;
+ }
+
+ public boolean isUserInRole(String role)
+ {
+ for (String r :_roles)
+ if (r.equals(role))
+ return true;
+ return false;
+ }
+
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
new file mode 100644
index 0000000000..06c589b03a
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
@@ -0,0 +1,90 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
+ */
+public class HashCrossContextPsuedoSession<T> implements CrossContextPsuedoSession<T>
+{
+ private final String _cookieName;
+
+ private final String _cookiePath;
+
+ private final Random _random = new SecureRandom();
+
+ private final Map<String, T> _data = new HashMap<String, T>();
+
+ public HashCrossContextPsuedoSession(String cookieName, String cookiePath)
+ {
+ this._cookieName = cookieName;
+ this._cookiePath = cookiePath == null ? "/" : cookiePath;
+ }
+
+ public T fetch(HttpServletRequest request)
+ {
+ for (Cookie cookie : request.getCookies())
+ {
+ if (_cookieName.equals(cookie.getName()))
+ {
+ String key = cookie.getValue();
+ return _data.get(key);
+ }
+ }
+ return null;
+ }
+
+ public void store(T datum, HttpServletResponse response)
+ {
+ String key;
+
+ synchronized (_data)
+ {
+ // Create new ID
+ while (true)
+ {
+ key = Long.toString(Math.abs(_random.nextLong()), 30 + (int) (System.currentTimeMillis() % 7));
+ if (!_data.containsKey(key)) break;
+ }
+
+ _data.put(key, datum);
+ }
+
+ Cookie cookie = new Cookie(_cookieName, key);
+ cookie.setPath(_cookiePath);
+ response.addCookie(cookie);
+ }
+
+ public void clear(HttpServletRequest request)
+ {
+ for (Cookie cookie : request.getCookies())
+ {
+ if (_cookieName.equals(cookie.getName()))
+ {
+ String key = cookie.getValue();
+ _data.remove(key);
+ break;
+ }
+ }
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java
new file mode 100644
index 0000000000..f82590390b
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java
@@ -0,0 +1,247 @@
+// ========================================================================
+// Copyright (c) 1996-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.jetty.http.security.Credential;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.Scanner.BulkListener;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+
+/* ------------------------------------------------------------ */
+/**
+ * Properties User Realm.
+ *
+ * An implementation of UserRealm that stores users and roles in-memory in
+ * HashMaps.
+ * <P>
+ * Typically these maps are populated by calling the load() method or passing a
+ * properties resource to the constructor. The format of the properties file is:
+ *
+ * <PRE>
+ * username: password [,rolename ...]
+ * </PRE>
+ *
+ * Passwords may be clear text, obfuscated or checksummed. The class
+ * com.eclipse.Util.Password should be used to generate obfuscated passwords or
+ * password checksums.
+ *
+ * If DIGEST Authentication is used, the password must be in a recoverable
+ * format, either plain text or OBF:.
+ *
+ * @see org.eclipse.jetty.security.Password
+ *
+ */
+public class HashLoginService extends MappedLoginService
+{
+ private String _config;
+ private Resource _configResource;
+ private Scanner _scanner;
+ private int _refreshInterval = 0;// default is not to reload
+
+ /* ------------------------------------------------------------ */
+ public HashLoginService()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ public HashLoginService(String name)
+ {
+ setName(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ public HashLoginService(String name, String config)
+ {
+ setName(name);
+ setConfig(config);
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getConfig()
+ {
+ return _config;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void getConfig(String config)
+ {
+ _config=config;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Resource getConfigResource()
+ {
+ return _configResource;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Load realm users from properties file. The property file maps usernames
+ * to password specs followed by an optional comma separated list of role
+ * names.
+ *
+ * @param config Filename or url of user properties file.
+ * @exception java.io.IOException if user properties file could not be
+ * loaded
+ */
+ public void setConfig(String config)
+ {
+ _config = config;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setRefreshInterval(int msec)
+ {
+ _refreshInterval = msec;
+ }
+
+ /* ------------------------------------------------------------ */
+ public int getRefreshInterval()
+ {
+ return _refreshInterval;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ protected UserIdentity loadUser(String username)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public void loadUsers() throws IOException
+ {
+ if (_config==null)
+ return;
+ _configResource = Resource.newResource(_config);
+
+ if (Log.isDebugEnabled()) Log.debug("Load " + this + " from " + _config);
+ Properties properties = new Properties();
+ properties.load(_configResource.getInputStream());
+ Set<String> known = new HashSet<String>();
+
+ for (Map.Entry<Object, Object> entry : properties.entrySet())
+ {
+ String username = ((String) entry.getKey()).trim();
+ String credentials = ((String) entry.getValue()).trim();
+ String roles = null;
+ int c = credentials.indexOf(',');
+ if (c > 0)
+ {
+ roles = credentials.substring(c + 1).trim();
+ credentials = credentials.substring(0, c).trim();
+ }
+
+ if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
+ {
+ String[] roleArray = UserIdentity.NO_ROLES;
+ if (roles != null && roles.length() > 0)
+ roleArray = roles.split(",");
+ known.add(username);
+ putUser(username,Credential.getCredential(credentials),roleArray);
+ }
+ }
+
+ Iterator<String> users = _users.keySet().iterator();
+ while(users.hasNext())
+ {
+ String user=users.next();
+ if (!known.contains(user))
+ users.remove();
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
+ */
+ protected void doStart() throws Exception
+ {
+ super.doStart();
+
+ if (getRefreshInterval() > 0)
+ {
+ _scanner = new Scanner();
+ _scanner.setScanInterval(getRefreshInterval());
+ List<File> dirList = new ArrayList<File>(1);
+ dirList.add(_configResource.getFile());
+ _scanner.setScanDirs(dirList);
+ _scanner.setFilenameFilter(new FilenameFilter()
+ {
+ public boolean accept(File dir, String name)
+ {
+ File f = new File(dir, name);
+ try
+ {
+ if (f.compareTo(_configResource.getFile()) == 0) return true;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ });
+ _scanner.addListener(new BulkListener()
+ {
+ public void filesChanged(List filenames) throws Exception
+ {
+ if (filenames == null) return;
+ if (filenames.isEmpty()) return;
+ if (filenames.size() == 1 && filenames.get(0).equals(_config)) loadUsers();
+ }
+
+ public String toString()
+ {
+ return "HashLoginService$Scanner";
+ }
+
+ });
+ _scanner.setReportExistingFilesOnStartup(false);
+ _scanner.setRecursive(false);
+ _scanner.start();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
+ */
+ protected void doStop() throws Exception
+ {
+ super.doStop();
+ if (_scanner != null) _scanner.stop();
+ _scanner = null;
+ }
+
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
new file mode 100644
index 0000000000..84e7071b8d
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
@@ -0,0 +1,99 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+/* ------------------------------------------------------------ */
+/**
+ * Associates UserIdentities from with threads and UserIdentity.Contexts.
+ *
+ */
+public interface IdentityService <SCOPED extends UserIdentity, RUNAS>
+{
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /** A scoped UserIdentity.
+ *
+ * An interface used to ob
+ *
+ */
+ interface Scoped
+ {
+ UserIdentity getScopedUserIdentity();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Associate the {@link UserIdentity} and {@link UserIdentity.Scope}
+ * with the current thread.
+ * @param user The current user.
+ * @param context The new scope.
+ * @return A scoped {@link UserIdentity}.
+ */
+ SCOPED associate(UserIdentity user, UserIdentity.Scope context);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Disassociate the current UserIdentity and reinstate the
+ * previousUser identity.
+ * TODO this might not be necessary. Both existing implementations are no-ops
+ * @param scoped SCOPED returned from previous associate call
+ */
+ void disassociate(SCOPED scoped);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Associate a runas Token with the current thread.
+ * @param token The runAsToken to associate.
+ * @return The previous runAsToken or null.
+ */
+ RUNAS associateRunAs(RunAsToken token);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Disassociate the current runAsToken from the thread
+ * and reassociate the previous token.
+ * @param token RUNAS returned from previous associateRunAs call
+ */
+ void disassociateRunAs(RUNAS token);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Create a new UserIdentity for use with this identity service.
+ * The UserIdentity should be immutable and able to be cached.
+ *
+ * @param subject Subject to include in UserIdentity
+ * @param userPrincipal Principal to include in UserIdentity. This will be returned from getUserPrincipal calls
+ * @param roles set of roles to include in UserIdentity.
+ * @return A new immutable UserIdententity
+ */
+ UserIdentity newUserIdentity(Subject subject, Principal userPrincipal, String[] roles);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Create a new RunAsToken from a runAsName (normally a role).
+ * @param runAsName Normally a role name
+ * @return A new immutable RunAsToken
+ */
+ RunAsToken newRunAsToken(String runAsName);
+
+ UserIdentity newSystemUserIdentity();
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java
new file mode 100644
index 0000000000..a994c45b5c
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java
@@ -0,0 +1,263 @@
+// ========================================================================
+// Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.jetty.http.security.Password;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+
+/* ------------------------------------------------------------ */
+/**
+ * HashMapped User Realm with JDBC as data source. JDBCLoginService extends
+ * HashULoginService and adds a method to fetch user information from database.
+ * The login() method checks the inherited Map for the user. If the user is not
+ * found, it will fetch details from the database and populate the inherited
+ * Map. It then calls the superclass login() method to perform the actual
+ * authentication. Periodically (controlled by configuration parameter),
+ * internal hashes are cleared. Caching can be disabled by setting cache refresh
+ * interval to zero. Uses one database connection that is initialized at
+ * startup. Reconnect on failures. authenticate() is 'synchronized'.
+ *
+ * An example properties file for configuration is in
+ * $JETTY_HOME/etc/jdbcRealm.properties
+ *
+ * @version $Id: JDBCLoginService.java 4792 2009-03-18 21:55:52Z gregw $
+ *
+ *
+ *
+ *
+ */
+
+public class JDBCLoginService extends MappedLoginService
+{
+ private String _config;
+ private String _jdbcDriver;
+ private String _url;
+ private String _userName;
+ private String _password;
+ private String _userTableKey;
+ private String _userTablePasswordField;
+ private String _roleTableRoleField;
+ private int _cacheTime;
+ private long _lastHashPurge;
+ private Connection _con;
+ private String _userSql;
+ private String _roleSql;
+
+
+ /* ------------------------------------------------------------ */
+ public JDBCLoginService()
+ throws IOException
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ public JDBCLoginService(String name)
+ throws IOException
+ {
+ setName(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ public JDBCLoginService(String name, String config)
+ throws IOException
+ {
+ setName(name);
+ setConfig(config);
+ }
+
+ /* ------------------------------------------------------------ */
+ public JDBCLoginService(String name, IdentityService identityService, String config)
+ throws IOException
+ {
+ setName(name);
+ setIdentityService(identityService);
+ setConfig(config);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.MappedLoginService#doStart()
+ */
+ @Override
+ protected void doStart() throws Exception
+ {
+ Properties properties = new Properties();
+ Resource resource = Resource.newResource(_config);
+ properties.load(resource.getInputStream());
+
+ _jdbcDriver = properties.getProperty("jdbcdriver");
+ _url = properties.getProperty("url");
+ _userName = properties.getProperty("username");
+ _password = properties.getProperty("password");
+ String _userTable = properties.getProperty("usertable");
+ _userTableKey = properties.getProperty("usertablekey");
+ String _userTableUserField = properties.getProperty("usertableuserfield");
+ _userTablePasswordField = properties.getProperty("usertablepasswordfield");
+ String _roleTable = properties.getProperty("roletable");
+ String _roleTableKey = properties.getProperty("roletablekey");
+ _roleTableRoleField = properties.getProperty("roletablerolefield");
+ String _userRoleTable = properties.getProperty("userroletable");
+ String _userRoleTableUserKey = properties.getProperty("userroletableuserkey");
+ String _userRoleTableRoleKey = properties.getProperty("userroletablerolekey");
+ _cacheTime = new Integer(properties.getProperty("cachetime"));
+
+ if (_jdbcDriver == null || _jdbcDriver.equals("")
+ || _url == null
+ || _url.equals("")
+ || _userName == null
+ || _userName.equals("")
+ || _password == null
+ || _cacheTime < 0)
+ {
+ if (Log.isDebugEnabled()) Log.debug("UserRealm " + getName() + " has not been properly configured");
+ }
+ _cacheTime *= 1000;
+ _lastHashPurge = 0;
+ _userSql = "select " + _userTableKey + "," + _userTablePasswordField + " from " + _userTable + " where " + _userTableUserField + " = ?";
+ _roleSql = "select r." + _roleTableRoleField
+ + " from "
+ + _roleTable
+ + " r, "
+ + _userRoleTable
+ + " u where u."
+ + _userRoleTableUserKey
+ + " = ?"
+ + " and r."
+ + _roleTableKey
+ + " = u."
+ + _userRoleTableRoleKey;
+
+ Loader.loadClass(this.getClass(), _jdbcDriver).newInstance();
+ connectDatabase();
+ super.doStart();
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public String getConfig()
+ {
+ return _config;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Load JDBC connection configuration from properties file.
+ *
+ * @param config Filename or url of user properties file.
+ * @exception java.io.IOException
+ */
+ public void setConfig(String config)
+ {
+ if (isRunning())
+ throw new IllegalStateException("Running");
+ _config=config;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * (re)Connect to database with parameters setup by loadConfig()
+ */
+ public void connectDatabase()
+ {
+ try
+ {
+ Class.forName(_jdbcDriver);
+ _con = DriverManager.getConnection(_url, _userName, _password);
+ }
+ catch (SQLException e)
+ {
+ Log.warn("UserRealm " + getName() + " could not connect to database; will try later", e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ Log.warn("UserRealm " + getName() + " could not connect to database; will try later", e);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public UserIdentity login(String username, Object credentials)
+ {
+ long now = System.currentTimeMillis();
+ if (now - _lastHashPurge > _cacheTime || _cacheTime == 0)
+ {
+ _users.clear();
+ _lastHashPurge = now;
+ }
+
+ return super.login(username,credentials);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ @Override
+ protected void loadUsers()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ protected UserIdentity loadUser(String username)
+ {
+ try
+ {
+ if (null == _con)
+ connectDatabase();
+
+ if (null == _con)
+ throw new SQLException("Can't connect to database");
+
+ PreparedStatement stat = _con.prepareStatement(_userSql);
+ stat.setObject(1, username);
+ ResultSet rs = stat.executeQuery();
+
+ if (rs.next())
+ {
+ int key = rs.getInt(_userTableKey);
+ String credentials = rs.getString(_userTablePasswordField);
+ stat.close();
+
+ stat = _con.prepareStatement(_roleSql);
+ stat.setInt(1, key);
+ rs = stat.executeQuery();
+ List<String> roles = new ArrayList<String>();
+ while (rs.next())
+ roles.add(rs.getString(_roleTableRoleField));
+
+ stat.close();
+ return putUser(username, new Password(credentials),roles.toArray(new String[roles.size()]));
+ }
+ }
+ catch (SQLException e)
+ {
+ Log.warn("UserRealm " + getName() + " could not load user information from database", e);
+ connectDatabase();
+ }
+ return null;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/LazyAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/LazyAuthentication.java
new file mode 100644
index 0000000000..99a8df7a3f
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/LazyAuthentication.java
@@ -0,0 +1,85 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class LazyAuthentication implements Authentication
+{
+ private static final Subject unauthenticatedSubject = new Subject();
+
+ private final Authenticator _serverAuthentication;
+ private final ServletRequest _request;
+ private final ServletResponse _response;
+
+ private Authentication _delegate;
+
+ public LazyAuthentication(Authenticator serverAuthentication, ServletRequest request, ServletResponse response)
+ {
+ if (serverAuthentication == null) throw new NullPointerException("No ServerAuthentication");
+ this._serverAuthentication = serverAuthentication;
+ this._request=request;
+ this._response=response;
+ }
+
+ private Authentication getDelegate()
+ {
+ if (_delegate == null)
+ {
+ try
+ {
+ _delegate = _serverAuthentication.validateRequest(_request, _response, false);
+ }
+ catch (ServerAuthException e)
+ {
+ _delegate = DefaultAuthentication.SEND_FAILURE_RESULTS;
+ }
+ }
+ return _delegate;
+ }
+
+ public Authentication.Status getAuthStatus()
+ {
+ return getDelegate().getAuthStatus();
+ }
+
+ public boolean isSuccess()
+ {
+ return getDelegate().isSuccess();
+ }
+
+ // for cleaning in secureResponse
+ public UserIdentity getUserIdentity()
+ {
+ return _delegate == null ? UserIdentity.UNAUTHENTICATED_IDENTITY: _delegate.getUserIdentity();
+ }
+
+ public String getAuthMethod()
+ {
+ return getDelegate().getAuthMethod();
+ }
+
+ public String toString()
+ {
+ return "{Lazy,"+_delegate+"}";
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java
new file mode 100644
index 0000000000..2b2cc6d44a
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java
@@ -0,0 +1,28 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+/**
+ * @version $Rev: 4734 $ $Date: 2009-03-07 18:46:18 +0100 (Sat, 07 Mar 2009) $
+ */
+public interface LoginService
+{
+ String getName();
+ UserIdentity login(String username,Object credentials);
+
+ IdentityService<UserIdentity,?> getIdentityService();
+ void setIdentityService(IdentityService<UserIdentity,?> service);
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java
new file mode 100644
index 0000000000..d4e88b3814
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java
@@ -0,0 +1,292 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+
+package org.eclipse.jetty.security;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.jetty.http.security.Credential;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+
+
+
+/* ------------------------------------------------------------ */
+/**
+ * A login service that keeps UserIdentities in a concurrent map
+ * either as the source or a cache of the users.
+ *
+ */
+public abstract class MappedLoginService extends AbstractLifeCycle implements LoginService
+{
+ protected IdentityService _identityService=new DefaultIdentityService();
+ protected String _name;
+ protected final ConcurrentMap<String, UserIdentity> _users=new ConcurrentHashMap<String, UserIdentity>();
+
+ /* ------------------------------------------------------------ */
+ protected MappedLoginService()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the name.
+ * @return the name
+ */
+ public String getName()
+ {
+ return _name;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the identityService.
+ * @return the identityService
+ */
+ public IdentityService getIdentityService()
+ {
+ return _identityService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the users.
+ * @return the users
+ */
+ public ConcurrentMap<String, UserIdentity> getUsers()
+ {
+ return _users;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the identityService.
+ * @param identityService the identityService to set
+ */
+ public void setIdentityService(IdentityService identityService)
+ {
+ if (isRunning())
+ throw new IllegalStateException("Running");
+ _identityService = identityService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the name.
+ * @param name the name to set
+ */
+ public void setName(String name)
+ {
+ if (isRunning())
+ throw new IllegalStateException("Running");
+ _name = name;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the users.
+ * @param users the users to set
+ */
+ public void setUsers(Map<String, UserIdentity> users)
+ {
+ if (isRunning())
+ throw new IllegalStateException("Running");
+ _users.clear();
+ _users.putAll(users);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
+ */
+ protected void doStart() throws Exception
+ {
+ loadUsers();
+ super.doStart();
+ }
+
+ /* ------------------------------------------------------------ */
+ protected void doStop() throws Exception
+ {
+ super.doStop();
+ }
+
+ /* ------------------------------------------------------------ */
+ public String toString()
+ {
+ return this.getClass().getSimpleName()+"["+_name+"]";
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Put user into realm.
+ * Called by implementations to put the user data loaded from
+ * file/db etc into the user structure.
+ * @param userName User name
+ * @param info a UserIdentity instance, or a String password or Credential instance
+ * @return User instance
+ */
+ protected synchronized UserIdentity putUser(String userName, Object info)
+ {
+ final UserIdentity identity;
+ if (info instanceof UserIdentity)
+ identity=(UserIdentity)info;
+ else
+ {
+ Credential credential = (info instanceof Credential)?(Credential)info:Credential.getCredential(info.toString());
+
+ Principal userPrincipal = new KnownUser(userName,credential);
+ Subject subject = new Subject();
+ subject.getPrincipals().add(userPrincipal);
+ subject.getPrivateCredentials().add(credential);
+ subject.setReadOnly();
+ identity=_identityService.newUserIdentity(subject,userPrincipal,UserIdentity.NO_ROLES);
+ }
+
+ _users.put(userName,identity);
+ return identity;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Put user into realm.
+ * @param userName
+ * @param credential
+ * @param roles
+ * @return UserIdentity
+ */
+ protected synchronized UserIdentity putUser(String userName, Credential credential, String[] roles)
+ {
+ Principal userPrincipal = new KnownUser(userName,credential);
+ Subject subject = new Subject();
+ subject.getPrincipals().add(userPrincipal);
+ subject.getPrivateCredentials().add(credential);
+
+ if (roles!=null)
+ for (String role : roles)
+ subject.getPrincipals().add(new RolePrincipal(role));
+
+ subject.setReadOnly();
+ UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
+ _users.put(userName,identity);
+ return identity;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object)
+ */
+ public UserIdentity login(String username, Object credentials)
+ {
+ UserIdentity user = _users.get(username);
+
+ if (user==null)
+ user = loadUser(username);
+
+ if (user!=null)
+ {
+ UserPrincipal principal = (UserPrincipal)user.getUserPrincipal();
+ if (principal.authenticate(credentials))
+ return user;
+ }
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected abstract UserIdentity loadUser(String username);
+
+ /* ------------------------------------------------------------ */
+ protected abstract void loadUsers() throws IOException;
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public interface UserPrincipal extends Principal
+ {
+ boolean authenticate(Object credentials);
+ public boolean isAuthenticated();
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public class RolePrincipal implements Principal
+ {
+ private final String _name;
+ public RolePrincipal(String name)
+ {
+ _name=name;
+ }
+ public String getName()
+ {
+ return _name;
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public static class Anonymous implements UserPrincipal
+ {
+ public boolean isAuthenticated()
+ {
+ return false;
+ }
+
+ public String getName()
+ {
+ return "Anonymous";
+ }
+
+ public boolean authenticate(Object credentials)
+ {
+ return false;
+ }
+
+ }
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public static class KnownUser implements UserPrincipal
+ {
+ private final String _name;
+ private final Credential _credential;
+
+ /* -------------------------------------------------------- */
+ public KnownUser(String name,Credential credential)
+ {
+ _name=name;
+ _credential=credential;
+ }
+
+ /* -------------------------------------------------------- */
+ public boolean authenticate(Object credentials)
+ {
+ return _credential!=null && _credential.check(credentials);
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getName()
+ {
+ return _name;
+ }
+
+ /* -------------------------------------------------------- */
+ public boolean isAuthenticated()
+ {
+ return true;
+ }
+ }
+}
+
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java
new file mode 100644
index 0000000000..d4d687f51c
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java
@@ -0,0 +1,135 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.util.Arrays;
+
+import org.eclipse.jetty.util.LazyList;
+
+/**
+ *
+ * Badly named class that holds the role and user data constraint info for a
+ * path/http method combination, extracted and combined from security
+ * constraints.
+ *
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class RoleInfo
+{
+ private final static String[] NO_ROLES={};
+ private boolean _isAnyRole;
+ private boolean _unchecked;
+ private boolean _forbidden;
+ private UserDataConstraint _userDataConstraint;
+
+ private String[] _roles = NO_ROLES;
+
+ public boolean isUnchecked()
+ {
+ return _unchecked;
+ }
+
+ public void setUnchecked(boolean unchecked)
+ {
+ this._unchecked = unchecked;
+ if (unchecked)
+ {
+ _forbidden=false;
+ _roles=NO_ROLES;
+ _isAnyRole=false;
+ }
+ }
+
+ public boolean isForbidden()
+ {
+ return _forbidden;
+ }
+
+ public void setForbidden(boolean forbidden)
+ {
+ this._forbidden = forbidden;
+ if (forbidden)
+ {
+ _unchecked = false;
+ _userDataConstraint = null;
+ _isAnyRole=false;
+ _roles=NO_ROLES;
+ }
+ }
+
+ public boolean isAnyRole()
+ {
+ return _isAnyRole;
+ }
+
+ public void setAnyRole(boolean anyRole)
+ {
+ this._isAnyRole=anyRole;
+ if (anyRole)
+ {
+ _unchecked = false;
+ _roles=NO_ROLES;
+ }
+ }
+
+ public UserDataConstraint getUserDataConstraint()
+ {
+ return _userDataConstraint;
+ }
+
+ public void setUserDataConstraint(UserDataConstraint userDataConstraint)
+ {
+ if (userDataConstraint == null) throw new NullPointerException("Null UserDataConstraint");
+ if (this._userDataConstraint == null)
+ {
+ this._userDataConstraint = userDataConstraint;
+ }
+ else
+ {
+ this._userDataConstraint = this._userDataConstraint.combine(userDataConstraint);
+ }
+ }
+
+ public String[] getRoles()
+ {
+ return _roles;
+ }
+
+ public void addRole(String role)
+ {
+ _roles=(String[])LazyList.addToArray(_roles,role,String.class);
+ }
+
+ public void combine(RoleInfo other)
+ {
+ if (other._forbidden)
+ setForbidden(true);
+ else if (other._unchecked)
+ setUnchecked(true);
+ else if (other._isAnyRole)
+ setAnyRole(true);
+ else if (!_isAnyRole)
+ {
+ for (String r : other._roles)
+ _roles=(String[])LazyList.addToArray(_roles,r,String.class);
+ }
+
+ setUserDataConstraint(other._userDataConstraint);
+ }
+
+ public String toString()
+ {
+ return "{RoleInfo"+(_forbidden?",F":"")+(_unchecked?",U":"")+(_isAnyRole?",*":Arrays.asList(_roles).toString())+"}";
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/RoleRunAsToken.java b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleRunAsToken.java
new file mode 100644
index 0000000000..02ee2d20e0
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleRunAsToken.java
@@ -0,0 +1,39 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+
+
+/**
+ * @version $Rev: 4701 $ $Date: 2009-03-03 13:01:26 +0100 (Tue, 03 Mar 2009) $
+ */
+public class RoleRunAsToken implements RunAsToken
+{
+ private final String _runAsRole;
+
+ public RoleRunAsToken(String runAsRole)
+ {
+ this._runAsRole = runAsRole;
+ }
+
+ public String getRunAsRole()
+ {
+ return _runAsRole;
+ }
+
+ public String toString()
+ {
+ return "RoleRunAsToken("+_runAsRole+")";
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/RunAsToken.java b/jetty-security/src/main/java/org/eclipse/jetty/security/RunAsToken.java
new file mode 100644
index 0000000000..7bf84ccd87
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/RunAsToken.java
@@ -0,0 +1,22 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+/**
+ * marker interface for run-as-role tokens
+ * @version $Rev: 4701 $ $Date: 2009-03-03 13:01:26 +0100 (Tue, 03 Mar 2009) $
+ */
+public interface RunAsToken
+{
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
new file mode 100644
index 0000000000..f550d23563
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
@@ -0,0 +1,524 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * Abstract SecurityHandler.
+ * Select and apply an {@link Authenticator} to a request.
+ * <p>
+ * The Authenticator may either be directly set on the handler
+ * or will be create during {@link #start()} with a call to
+ * either the default or set AuthenticatorFactory.
+ */
+public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.Configuration
+{
+ /* ------------------------------------------------------------ */
+ private boolean _checkWelcomeFiles = false;
+ private Authenticator _authenticator;
+ private Authenticator.Factory _authenticatorFactory=new DefaultAuthenticatorFactory();
+ private boolean _isLazy=true;
+ private String _realmName;
+ private String _authMethod;
+ private final Map<String,String> _initParameters=new HashMap<String,String>();
+ private LoginService _loginService;
+ private boolean _loginServiceShared;
+ private IdentityService<UserIdentity,?> _identityService;
+
+ /* ------------------------------------------------------------ */
+ protected SecurityHandler()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the identityService.
+ * @return the identityService
+ */
+ public IdentityService<UserIdentity,?> getIdentityService()
+ {
+ return _identityService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the identityService.
+ * @param identityService the identityService to set
+ */
+ public void setIdentityService(IdentityService<UserIdentity,?> identityService)
+ {
+ if (isStarted())
+ throw new IllegalStateException("Started");
+ _identityService = identityService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the loginService.
+ * @return the loginService
+ */
+ public LoginService getLoginService()
+ {
+ return _loginService;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the loginService.
+ * @param loginService the loginService to set
+ */
+ public void setLoginService(LoginService loginService)
+ {
+ if (isStarted())
+ throw new IllegalStateException("Started");
+ _loginService = loginService;
+ _loginServiceShared=false;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public Authenticator getAuthenticator()
+ {
+ return _authenticator;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the authenticator.
+ * @param authenticator
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setAuthenticator(Authenticator authenticator)
+ {
+ if (isStarted())
+ throw new IllegalStateException("Started");
+ _authenticator = authenticator;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the authenticatorFactory
+ */
+ public Authenticator.Factory getAuthenticatorFactory()
+ {
+ return _authenticatorFactory;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param authenticatorFactory the authenticatorFactory to set
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ _authenticatorFactory = authenticatorFactory;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the isLazy
+ */
+ public boolean isLazy()
+ {
+ return _isLazy;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param isLazy the isLazy to set
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setLazy(boolean isLazy)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ _isLazy = isLazy;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the realmName
+ */
+ public String getRealmName()
+ {
+ return _realmName;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param realmName the realmName to set
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setRealmName(String realmName)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ _realmName = realmName;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the authMethod
+ */
+ public String getAuthMethod()
+ {
+ return _authMethod;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param authMethod the authMethod to set
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setAuthMethod(String authMethod)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ _authMethod = authMethod;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return True if forwards to welcome files are authenticated
+ */
+ public boolean isCheckWelcomeFiles()
+ {
+ return _checkWelcomeFiles;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param authenticateWelcomeFiles True if forwards to welcome files are
+ * authenticated
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public void setCheckWelcomeFiles(boolean authenticateWelcomeFiles)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ _checkWelcomeFiles = authenticateWelcomeFiles;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getInitParameter(String key)
+ {
+ return _initParameters.get(key);
+ }
+
+ /* ------------------------------------------------------------ */
+ public Set<String> getInitParameterNames()
+ {
+ return _initParameters.keySet();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set an initialization parameter.
+ * @param key
+ * @param value
+ * @return previous value
+ * @throws IllegalStateException if the SecurityHandler is running
+ */
+ public String setInitParameter(String key, String value)
+ {
+ if (isRunning())
+ throw new IllegalStateException("running");
+ return _initParameters.put(key,value);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ protected LoginService findLoginService()
+ {
+ List<LoginService> list = getServer().getBeans(LoginService.class);
+
+ for (LoginService service : list)
+ if (service.getName().equals(getRealmName()))
+ return service;
+ if (list.size()>0)
+ return list.get(0);
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ protected IdentityService<UserIdentity,?> findIdentityService()
+ {
+ List<IdentityService> services = getServer().getBeans(IdentityService.class);
+ if (services!=null && services.size()>0)
+ return services.get(0);
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ */
+ protected void doStart()
+ throws Exception
+ {
+ // complicated resolution of login and identity service to handle
+ // many different ways these can be constructed and injected.
+
+ if (_loginService==null)
+ {
+ _loginService=findLoginService();
+ if (_loginService!=null)
+ _loginServiceShared=true;
+ }
+
+ if (_identityService==null)
+ {
+ if (_loginService!=null)
+ _identityService=_loginService.getIdentityService();
+
+ if (_identityService==null)
+ _identityService=findIdentityService();
+
+ if (_identityService==null)
+ _identityService=new DefaultIdentityService();
+ }
+
+ if (_loginService!=null)
+ {
+ if (_loginService.getIdentityService()==null)
+ _loginService.setIdentityService(_identityService);
+ else if (_loginService.getIdentityService()!=_identityService)
+ throw new IllegalStateException("LoginService has different IdentityService to "+this);
+ }
+
+ if (!_loginServiceShared && _loginService instanceof LifeCycle)
+ ((LifeCycle)_loginService).start();
+
+ if (_authenticator==null && _authenticatorFactory!=null)
+ {
+ _authenticator=_authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this);
+ if (_authenticator!=null)
+ _authMethod=_authenticator.getAuthMethod();
+ }
+
+ if (_authenticator==null)
+ {
+ Log.warn("No ServerAuthentication for "+this);
+ throw new IllegalStateException("No ServerAuthentication");
+ }
+
+ _authenticator.setConfiguration(this);
+ if (_authenticator instanceof LifeCycle)
+ ((LifeCycle)_authenticator).start();
+
+
+ super.doStart();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStop()
+ */
+ @Override
+ protected void doStop() throws Exception
+ {
+ super.doStop();
+
+ if (!_loginServiceShared && _loginService instanceof LifeCycle)
+ ((LifeCycle)_loginService).stop();
+
+ }
+
+ protected boolean checkSecurity(Request request)
+ {
+ switch(request.getDispatcherType())
+ {
+ case REQUEST:
+ case ASYNC:
+ return true;
+ case FORWARD:
+ if (_checkWelcomeFiles && request.getAttribute("org.eclipse.jetty.server.welcome") != null)
+ {
+ request.removeAttribute("org.eclipse.jetty.server.welcome");
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see org.eclipse.jetty.server.Handler#handle(java.lang.String,
+ * javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse, int)
+ */
+ public void handle(String pathInContext, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ final Request base_request = (request instanceof Request) ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
+ final Response base_response = (response instanceof Response) ? (Response) response : HttpConnection.getCurrentConnection().getResponse();
+ final Handler handler=getHandler();
+
+ if (handler==null)
+ return;
+
+ if (checkSecurity(base_request))
+ {
+ Object constraintInfo = prepareConstraintInfo(pathInContext, base_request);
+
+ // Check data constraints
+ if (!checkUserDataPermissions(pathInContext, base_request, base_response, constraintInfo))
+ {
+ if (!base_request.isHandled())
+ {
+ response.sendError(Response.SC_FORBIDDEN);
+ base_request.setHandled(true);
+ }
+ return;
+ }
+
+ // is Auth mandatory?
+ boolean isAuthMandatory = isAuthMandatory(base_request, base_response, constraintInfo);
+
+ // check authentication
+ UserIdentity old_user_identity=base_request.getUserIdentity();
+ try
+ {
+ final Authenticator authenticator = _authenticator;
+ Authentication authentication = authenticator.validateRequest(request, response, isAuthMandatory);
+
+ if (authentication.getAuthStatus() == Authentication.Status.SUCCESS)
+ {
+ final UserIdentity user_identity=authentication.getUserIdentity();
+ base_request.setAuthType(authentication.getAuthMethod());
+ base_request.setUserIdentity(user_identity);
+
+ if (isAuthMandatory && !checkWebResourcePermissions(pathInContext, base_request, base_response, constraintInfo, user_identity))
+ {
+ response.sendError(Response.SC_FORBIDDEN, "User not in required role");
+ base_request.setHandled(true);
+ return;
+ }
+
+ handler.handle(pathInContext, request, response);
+
+ authenticator.secureResponse(request, response, isAuthMandatory, authentication);
+ }
+ else
+ {
+ base_request.setHandled(true);
+ }
+ }
+ catch (ServerAuthException e)
+ {
+ // jaspi 3.8.3 send HTTP 500 internal server error, with message
+ // from AuthException
+ response.sendError(Response.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+ finally
+ {
+ base_request.setUserIdentity(old_user_identity);
+ }
+ }
+ else
+ handler.handle(pathInContext, request, response);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ protected abstract Object prepareConstraintInfo(String pathInContext, Request request);
+
+ /* ------------------------------------------------------------ */
+ protected abstract boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException;
+
+ /* ------------------------------------------------------------ */
+ protected abstract boolean isAuthMandatory(Request base_request, Response base_response, Object constraintInfo);
+
+ /* ------------------------------------------------------------ */
+ protected abstract boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo,
+ UserIdentity userIdentity) throws IOException;
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public class NotChecked implements Principal
+ {
+ public String getName()
+ {
+ return null;
+ }
+
+ public String toString()
+ {
+ return "NOT CHECKED";
+ }
+
+ public SecurityHandler getSecurityHandler()
+ {
+ return SecurityHandler.this;
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ public static Principal __NO_USER = new Principal()
+ {
+ public String getName()
+ {
+ return null;
+ }
+
+ public String toString()
+ {
+ return "No User";
+ }
+ };
+
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /**
+ * Nobody user. The Nobody UserPrincipal is used to indicate a partial state
+ * of authentication. A request with a Nobody UserPrincipal will be allowed
+ * past all authentication constraints - but will not be considered an
+ * authenticated request. It can be used by Authenticators such as
+ * FormAuthenticator to allow access to logon and error pages within an
+ * authenticated URI tree.
+ */
+ public static Principal __NOBODY = new Principal()
+ {
+ public String getName()
+ {
+ return "Nobody";
+ }
+
+ public String toString()
+ {
+ return getName();
+ }
+ };
+
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ServerAuthException.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ServerAuthException.java
new file mode 100644
index 0000000000..d0f26943bf
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ServerAuthException.java
@@ -0,0 +1,42 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ */
+public class ServerAuthException extends GeneralSecurityException
+{
+
+ public ServerAuthException()
+ {
+ }
+
+ public ServerAuthException(String s)
+ {
+ super(s);
+ }
+
+ public ServerAuthException(String s, Throwable throwable)
+ {
+ super(s, throwable);
+ }
+
+ public ServerAuthException(Throwable throwable)
+ {
+ super(throwable);
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/UserDataConstraint.java b/jetty-security/src/main/java/org/eclipse/jetty/security/UserDataConstraint.java
new file mode 100644
index 0000000000..e1d4369242
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/UserDataConstraint.java
@@ -0,0 +1,35 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security;
+
+/**
+ * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ */
+public enum UserDataConstraint
+{
+ None, Integral, Confidential;
+
+ public static UserDataConstraint get(int dataConstraint)
+ {
+ if (dataConstraint < -1 || dataConstraint > 2) throw new IllegalArgumentException("Expected -1, 0, 1, or 2, not: " + dataConstraint);
+ if (dataConstraint == -1) return None;
+ return values()[dataConstraint];
+ }
+
+ public UserDataConstraint combine(UserDataConstraint other)
+ {
+ if (this.compareTo(other) < 0) return this;
+ return other;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
new file mode 100644
index 0000000000..d91251e651
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
@@ -0,0 +1,106 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.io.IOException;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.security.B64Code;
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.DefaultAuthentication;
+import org.eclipse.jetty.security.DefaultUserIdentity;
+import org.eclipse.jetty.security.ServerAuthException;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.StringUtil;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class BasicAuthenticator extends LoginAuthenticator
+{
+ /* ------------------------------------------------------------ */
+ /**
+ * @param loginService
+ */
+ public BasicAuthenticator()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.Authenticator#getAuthMethod()
+ */
+ public String getAuthMethod()
+ {
+ return Constraint.__BASIC_AUTH;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.Authenticator#validateRequest(javax.servlet.ServletRequest, javax.servlet.ServletResponse, boolean)
+ */
+ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
+ {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+ try
+ {
+ if (credentials != null)
+ {
+ credentials = credentials.substring(credentials.indexOf(' ')+1);
+ credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
+ int i = credentials.indexOf(':');
+ String username = credentials.substring(0,i);
+ String password = credentials.substring(i+1);
+
+ UserIdentity user = _loginService.login(username,password);
+ if (user!=null)
+ {
+ if (user instanceof DefaultUserIdentity)
+ return ((DefaultUserIdentity)user).SUCCESSFUL_BASIC;
+ return new DefaultAuthentication(Authentication.Status.SUCCESS,Constraint.__BASIC_AUTH,user);
+ }
+ }
+
+ if (!mandatory)
+ {
+ return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS;
+ }
+ response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "basic realm=\"" + _loginService.getName() + '"');
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return DefaultAuthentication.SEND_CONTINUE_RESULTS;
+ }
+ catch (IOException e)
+ {
+ throw new ServerAuthException(e);
+ }
+ }
+
+ // most likely validatedUser is not needed here.
+
+ // corrct?
+ public Authentication.Status secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication validatedUser) throws ServerAuthException
+ {
+ return Authentication.Status.SUCCESS;
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
new file mode 100644
index 0000000000..4b2cd51997
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
@@ -0,0 +1,98 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.security.B64Code;
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.DefaultAuthentication;
+import org.eclipse.jetty.security.ServerAuthException;
+import org.eclipse.jetty.server.UserIdentity;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class ClientCertAuthenticator extends LoginAuthenticator
+{
+ public ClientCertAuthenticator()
+ {
+ super();
+ }
+
+ public String getAuthMethod()
+ {
+ return Constraint.__CERT_AUTH;
+ }
+
+ /**
+ * TODO what should happen if an insecure page is accessed without a client
+ * cert? Current code requires a client cert always but allows access to
+ * insecure pages if it is not recognized.
+ *
+ * @return
+ * @throws ServerAuthException
+ */
+ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
+ {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
+
+ try
+ {
+ // Need certificates.
+ if (certs == null || certs.length == 0 || certs[0] == null)
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN,
+ "A client certificate is required for accessing this web application but the server's listener is not configured for mutual authentication (or the client did not provide a certificate).");
+ return DefaultAuthentication.SEND_FAILURE_RESULTS;
+ }
+
+ Principal principal = certs[0].getSubjectDN();
+ if (principal == null) principal = certs[0].getIssuerDN();
+ final String username = principal == null ? "clientcert" : principal.getName();
+
+ // TODO no idea if this is correct
+ final char[] credential = B64Code.encode(certs[0].getSignature());
+
+ UserIdentity user = _loginService.login(username,credential);
+ if (user!=null)
+ return new DefaultAuthentication(Authentication.Status.SUCCESS,Constraint.__CERT_AUTH2,user);
+
+ if (!mandatory)
+ {
+ return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS;
+ }
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "The provided client certificate does not correspond to a trusted user.");
+ return DefaultAuthentication.SEND_FAILURE_RESULTS;
+ }
+ catch (IOException e)
+ {
+ throw new ServerAuthException(e.getMessage());
+ }
+ }
+
+ public Authentication.Status secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication validatedUser) throws ServerAuthException
+ {
+ return Authentication.Status.SUCCESS;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DelegateAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DelegateAuthenticator.java
new file mode 100644
index 0000000000..e7343cc7d2
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DelegateAuthenticator.java
@@ -0,0 +1,57 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.Authenticator;
+import org.eclipse.jetty.security.ServerAuthException;
+
+public class DelegateAuthenticator implements Authenticator
+{
+ protected final Authenticator _delegate;
+
+ public void setConfiguration(Configuration configuration)
+ {
+ _delegate.setConfiguration(configuration);
+ }
+
+ public String getAuthMethod()
+ {
+ return _delegate.getAuthMethod();
+ }
+
+ public DelegateAuthenticator(Authenticator delegate)
+ {
+ _delegate=delegate;
+ }
+
+ public Authenticator getDelegate()
+ {
+ return _delegate;
+ }
+
+ public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean manditory) throws ServerAuthException
+ {
+ return _delegate.validateRequest(request, response, manditory);
+ }
+
+ public Authentication.Status secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication validatedUser) throws ServerAuthException
+ {
+ return _delegate.secureResponse(req,res, mandatory, validatedUser);
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
new file mode 100644
index 0000000000..dad736a197
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
@@ -0,0 +1,333 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.security.B64Code;
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.http.security.Credential;
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.DefaultAuthentication;
+import org.eclipse.jetty.security.DefaultUserIdentity;
+import org.eclipse.jetty.security.ServerAuthException;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class DigestAuthenticator extends LoginAuthenticator
+{
+ protected long _maxNonceAge = 0;
+ protected long _nonceSecret = this.hashCode() ^ System.currentTimeMillis();
+ protected boolean _useStale = false;
+
+ public DigestAuthenticator()
+ {
+ super();
+ }
+
+ public String getAuthMethod()
+ {
+ return Constraint.__DIGEST_AUTH;
+ }
+
+ public Authentication.Status secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication validatedUser) throws ServerAuthException
+ {
+ return Authentication.Status.SUCCESS;
+ }
+
+ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
+ {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+ try
+ {
+ boolean stale = false;
+ if (credentials != null)
+ {
+ if (Log.isDebugEnabled()) Log.debug("Credentials: " + credentials);
+ QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(credentials, "=, ", true, false);
+ final Digest digest = new Digest(request.getMethod());
+ String last = null;
+ String name = null;
+
+ while (tokenizer.hasMoreTokens())
+ {
+ String tok = tokenizer.nextToken();
+ char c = (tok.length() == 1) ? tok.charAt(0) : '\0';
+
+ switch (c)
+ {
+ case '=':
+ name = last;
+ last = tok;
+ break;
+ case ',':
+ name = null;
+ case ' ':
+ break;
+
+ default:
+ last = tok;
+ if (name != null)
+ {
+ if ("username".equalsIgnoreCase(name))
+ digest.username = tok;
+ else if ("realm".equalsIgnoreCase(name))
+ digest.realm = tok;
+ else if ("nonce".equalsIgnoreCase(name))
+ digest.nonce = tok;
+ else if ("nc".equalsIgnoreCase(name))
+ digest.nc = tok;
+ else if ("cnonce".equalsIgnoreCase(name))
+ digest.cnonce = tok;
+ else if ("qop".equalsIgnoreCase(name))
+ digest.qop = tok;
+ else if ("uri".equalsIgnoreCase(name))
+ digest.uri = tok;
+ else if ("response".equalsIgnoreCase(name)) digest.response = tok;
+ break;
+ }
+ }
+ }
+
+ int n = checkNonce(digest.nonce, (Request)request);
+
+ if (n > 0)
+ {
+ UserIdentity user = _loginService.login(digest.username,digest);
+ if (user!=null)
+ {
+ if (user instanceof DefaultUserIdentity)
+ return ((DefaultUserIdentity)user).SUCCESSFUL_BASIC;
+ return new DefaultAuthentication(Authentication.Status.SUCCESS,Constraint.__DIGEST_AUTH,user);
+ }
+ }
+ else if (n == 0) stale = true;
+
+ }
+
+ if (!mandatory) { return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS; }
+ String domain = request.getContextPath();
+ if (domain == null) domain = "/";
+ response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"" + _loginService.getName()
+ + "\", domain=\""
+ + domain
+ + "\", nonce=\""
+ + newNonce((Request)request)
+ + "\", algorithm=MD5, qop=\"auth\""
+ + (_useStale ? (" stale=" + stale) : ""));
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return DefaultAuthentication.SEND_CONTINUE_RESULTS;
+ }
+ catch (IOException e)
+ {
+ throw new ServerAuthException(e);
+ }
+
+ }
+
+ public String newNonce(Request request)
+ {
+ long ts=request.getTimeStamp();
+ long sk = _nonceSecret;
+
+ byte[] nounce = new byte[24];
+ for (int i = 0; i < 8; i++)
+ {
+ nounce[i] = (byte) (ts & 0xff);
+ ts = ts >> 8;
+ nounce[8 + i] = (byte) (sk & 0xff);
+ sk = sk >> 8;
+ }
+
+ byte[] hash = null;
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.reset();
+ md.update(nounce, 0, 16);
+ hash = md.digest();
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ }
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ nounce[8 + i] = hash[i];
+ if (i == 23) break;
+ }
+
+ return new String(B64Code.encode(nounce));
+ }
+
+ /**
+ * @param nonce nonce to check
+ * @param request
+ * @return -1 for a bad nonce, 0 for a stale none, 1 for a good nonce
+ */
+ /* ------------------------------------------------------------ */
+ private int checkNonce(String nonce, Request request)
+ {
+ try
+ {
+ byte[] n = B64Code.decode(nonce.toCharArray());
+ if (n.length != 24) return -1;
+
+ long ts = 0;
+ long sk = _nonceSecret;
+ byte[] n2 = new byte[16];
+ System.arraycopy(n, 0, n2, 0, 8);
+ for (int i = 0; i < 8; i++)
+ {
+ n2[8 + i] = (byte) (sk & 0xff);
+ sk = sk >> 8;
+ ts = (ts << 8) + (0xff & (long) n[7 - i]);
+ }
+
+ long age = request.getTimeStamp() - ts;
+ if (Log.isDebugEnabled()) Log.debug("age=" + age);
+
+ byte[] hash = null;
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.reset();
+ md.update(n2, 0, 16);
+ hash = md.digest();
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ }
+
+ for (int i = 0; i < 16; i++)
+ if (n[i + 8] != hash[i]) return -1;
+
+ if (_maxNonceAge > 0 && (age < 0 || age > _maxNonceAge)) return 0; // stale
+
+ return 1;
+ }
+ catch (Exception e)
+ {
+ Log.ignore(e);
+ }
+ return -1;
+ }
+
+ private static class Digest extends Credential
+ {
+ String method = null;
+ String username = null;
+ String realm = null;
+ String nonce = null;
+ String nc = null;
+ String cnonce = null;
+ String qop = null;
+ String uri = null;
+ String response = null;
+
+ /* ------------------------------------------------------------ */
+ Digest(String m)
+ {
+ method = m;
+ }
+
+ /* ------------------------------------------------------------ */
+ public boolean check(Object credentials)
+ {
+ String password = (credentials instanceof String) ? (String) credentials : credentials.toString();
+
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] ha1;
+ if (credentials instanceof Credential.MD5)
+ {
+ // Credentials are already a MD5 digest - assume it's in
+ // form user:realm:password (we have no way to know since
+ // it's a digest, alright?)
+ ha1 = ((Credential.MD5) credentials).getDigest();
+ }
+ else
+ {
+ // calc A1 digest
+ md.update(username.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(realm.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(password.getBytes(StringUtil.__ISO_8859_1));
+ ha1 = md.digest();
+ }
+ // calc A2 digest
+ md.reset();
+ md.update(method.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(uri.getBytes(StringUtil.__ISO_8859_1));
+ byte[] ha2 = md.digest();
+
+ // calc digest
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":"
+ // nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" H(A2) )
+ // <">
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2)
+ // ) > <">
+
+ md.update(TypeUtil.toString(ha1, 16).getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(nonce.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(nc.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(cnonce.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(qop.getBytes(StringUtil.__ISO_8859_1));
+ md.update((byte) ':');
+ md.update(TypeUtil.toString(ha2, 16).getBytes(StringUtil.__ISO_8859_1));
+ byte[] digest = md.digest();
+
+ // check digest
+ return (TypeUtil.toString(digest, 16).equalsIgnoreCase(response));
+ }
+ catch (Exception e)
+ {
+ Log.warn(e);
+ }
+
+ return false;
+ }
+
+ public String toString()
+ {
+ return username + "," + response;
+ }
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java
new file mode 100644
index 0000000000..c01fe7258f
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java
@@ -0,0 +1,219 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.http.security.Constraint;
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.DefaultAuthentication;
+import org.eclipse.jetty.security.ServerAuthException;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class FormAuthenticator extends LoginAuthenticator
+{
+ public final static String __FORM_LOGIN_PAGE="org.eclipse.jetty.security.form_login_page";
+ public final static String __FORM_ERROR_PAGE="org.eclipse.jetty.security.form_error_page";
+ public final static String __J_URI = "org.eclipse.jetty.util.URI";
+ public final static String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth";
+ public final static String __J_SECURITY_CHECK = "/j_security_check";
+ public final static String __J_USERNAME = "j_username";
+ public final static String __J_PASSWORD = "j_password";
+ private String _formErrorPage;
+ private String _formErrorPath;
+ private String _formLoginPage;
+ private String _formLoginPath;
+
+ public FormAuthenticator()
+ {
+ }
+
+ /* ------------------------------------------------------------ */
+ public FormAuthenticator(String login,String error)
+ {
+ if (login!=null)
+ setLoginPage(login);
+ if (error!=null)
+ setErrorPage(error);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.security.authentication.LoginAuthenticator#setConfiguration(org.eclipse.jetty.security.Authenticator.Configuration)
+ */
+ @Override
+ public void setConfiguration(Configuration configuration)
+ {
+ super.setConfiguration(configuration);
+ String login=configuration.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE);
+ if (login!=null)
+ setLoginPage(login);
+ String error=configuration.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE);
+ if (error!=null)
+ setErrorPage(error);
+ }
+
+
+
+ public String getAuthMethod()
+ {
+ return Constraint.__FORM_AUTH;
+ }
+
+ private void setLoginPage(String path)
+ {
+ if (!path.startsWith("/"))
+ {
+ Log.warn("form-login-page must start with /");
+ path = "/" + path;
+ }
+ _formLoginPage = path;
+ _formLoginPath = path;
+ if (_formLoginPath.indexOf('?') > 0)
+ _formLoginPath = _formLoginPath.substring(0, _formLoginPath.indexOf('?'));
+ }
+
+ /* ------------------------------------------------------------ */
+ private void setErrorPage(String path)
+ {
+ if (path == null || path.trim().length() == 0)
+ {
+ _formErrorPath = null;
+ _formErrorPage = null;
+ }
+ else
+ {
+ if (!path.startsWith("/"))
+ {
+ Log.warn("form-error-page must start with /");
+ path = "/" + path;
+ }
+ _formErrorPage = path;
+ _formErrorPath = path;
+
+ if (_formErrorPath.indexOf('?') > 0)
+ _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?'));
+ }
+ }
+
+ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
+ {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ HttpSession session = request.getSession(mandatory);
+ String uri = request.getPathInfo();
+ // not mandatory and not authenticated
+ if (session == null || isLoginOrErrorPage(uri))
+ {
+ return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS;
+ }
+
+
+ try
+ {
+ // Handle a request for authentication.
+ // TODO perhaps j_securitycheck can be uri suffix?
+ if (uri.endsWith(__J_SECURITY_CHECK))
+ {
+ final String username = request.getParameter(__J_USERNAME);
+ final char[] password = request.getParameter(__J_PASSWORD).toCharArray();
+
+ UserIdentity user = _loginService.login(username,password);
+ if (user!=null)
+ {
+ // Redirect to original request
+ String nuri = (String) session.getAttribute(__J_URI);
+ if (nuri == null || nuri.length() == 0)
+ {
+ nuri = request.getContextPath();
+ if (nuri.length() == 0) nuri = URIUtil.SLASH;
+ }
+ // TODO shouldn't we forward to original URI instead?
+ session.removeAttribute(__J_URI); // Remove popped return URI.
+ response.setContentLength(0);
+ response.sendRedirect(response.encodeRedirectURL(nuri));
+ return new DefaultAuthentication(Authentication.Status.SEND_SUCCESS,Constraint.__FORM_AUTH,user);
+ }
+
+ // not authenticated
+ if (Log.isDebugEnabled()) Log.debug("Form authentication FAILED for " + StringUtil.printable(username));
+ if (_formErrorPage == null)
+ {
+ if (response != null)
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+ else
+ {
+// response.setContentLength(0); //????
+ RequestDispatcher dispatcher = request.getRequestDispatcher(_formErrorPage);
+ dispatcher.forward(request, response);
+ }
+ // TODO is this correct response if isMandatory false??? Can
+ // that occur?
+ return DefaultAuthentication.SEND_FAILURE_RESULTS;
+ }
+ // Check if the session is already authenticated.
+
+ // Don't authenticate authform or errorpage
+ if (!mandatory)
+ // TODO verify this is correct action
+ return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS;
+
+ // redirect to login page
+ if (request.getQueryString() != null)
+ uri += "?" + request.getQueryString();
+ //TODO is this safe if the client is sending several requests concurrently in the same session to secured resources?
+ session.setAttribute(__J_URI, request.getScheme() + "://"
+ + request.getServerName()
+ + ":"
+ + request.getServerPort()
+ + URIUtil.addPaths(request.getContextPath(), uri));
+ RequestDispatcher dispatcher = request.getRequestDispatcher(_formLoginPage);
+ dispatcher.forward(request, response);
+ return DefaultAuthentication.SEND_CONTINUE_RESULTS;
+ }
+ catch (IOException e)
+ {
+ throw new ServerAuthException(e);
+ }
+ catch (ServletException e)
+ {
+ throw new ServerAuthException(e);
+ }
+ }
+
+ public boolean isLoginOrErrorPage(String pathInContext)
+ {
+ return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
+ }
+
+ public Authentication.Status secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication validatedUser) throws ServerAuthException
+ {
+ return Authentication.Status.SUCCESS;
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LazyAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LazyAuthenticator.java
new file mode 100644
index 0000000000..65c237bb35
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LazyAuthenticator.java
@@ -0,0 +1,45 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.Authenticator;
+import org.eclipse.jetty.security.LazyAuthentication;
+import org.eclipse.jetty.security.ServerAuthException;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class LazyAuthenticator extends DelegateAuthenticator
+{
+ public LazyAuthenticator(Authenticator delegate)
+ {
+ super(delegate);
+ }
+
+ /**
+ * @see org.eclipse.jetty.security.Authenticator#validateRequest(ServletRequest, ServletResponse, boolean)
+ */
+ public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
+ {
+ if (!mandatory)
+ {
+ return new LazyAuthentication(_delegate,request,response);
+ }
+ return _delegate.validateRequest(request, response, mandatory);
+ }
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
new file mode 100644
index 0000000000..444d249853
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
@@ -0,0 +1,44 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import org.eclipse.jetty.security.Authenticator;
+import org.eclipse.jetty.security.IdentityService;
+import org.eclipse.jetty.security.LoginService;
+
+public abstract class LoginAuthenticator implements Authenticator
+{
+ protected LoginService _loginService;
+ protected IdentityService _identityService;
+
+ protected LoginAuthenticator()
+ {
+ }
+
+ public void setConfiguration(Configuration configuration)
+ {
+ _loginService=configuration.getLoginService();
+ if (_loginService==null)
+ throw new IllegalStateException("No LoginService for "+this);
+ _identityService=configuration.getIdentityService();
+ if (_identityService==null)
+ throw new IllegalStateException("No IdentityService for "+this);
+ }
+
+ public LoginService getLoginService()
+ {
+ return _loginService;
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallback.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallback.java
new file mode 100644
index 0000000000..06a285c298
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallback.java
@@ -0,0 +1,50 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+
+/**
+ * This is similar to the jaspi PasswordValidationCallback but includes user
+ * principal and group info as well.
+ *
+ * @version $Rev: 4792 $ $Date: 2009-03-18 22:55:52 +0100 (Wed, 18 Mar 2009) $
+ */
+public interface LoginCallback
+{
+ public Subject getSubject();
+
+ public String getUserName();
+
+ public Object getCredential();
+
+ public boolean isSuccess();
+
+ public void setSuccess(boolean success);
+
+ public Principal getUserPrincipal();
+
+ public void setUserPrincipal(Principal userPrincipal);
+
+ public String[] getRoles();
+
+ public void setRoles(String[] roles);
+
+ public void clearPassword();
+
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java
new file mode 100644
index 0000000000..bb1ee36898
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java
@@ -0,0 +1,104 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.jetty.server.UserIdentity;
+
+/**
+ * This is similar to the jaspi PasswordValidationCallback but includes user
+ * principal and group info as well.
+ *
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class LoginCallbackImpl implements LoginCallback
+{
+ // initial data
+ private final Subject subject;
+
+ private final String userName;
+
+ private Object credential;
+
+ private boolean success;
+
+ private Principal userPrincipal;
+
+ private String[] roles = UserIdentity.NO_ROLES;
+
+ //TODO could use Credential instance instead of Object if Basic/Form create a Password object
+ public LoginCallbackImpl (Subject subject, String userName, Object credential)
+ {
+ this.subject = subject;
+ this.userName = userName;
+ this.credential = credential;
+ }
+
+ public Subject getSubject()
+ {
+ return subject;
+ }
+
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ public Object getCredential()
+ {
+ return credential;
+ }
+
+ public boolean isSuccess()
+ {
+ return success;
+ }
+
+ public void setSuccess(boolean success)
+ {
+ this.success = success;
+ }
+
+ public Principal getUserPrincipal()
+ {
+ return userPrincipal;
+ }
+
+ public void setUserPrincipal(Principal userPrincipal)
+ {
+ this.userPrincipal = userPrincipal;
+ }
+
+ public String[] getRoles()
+ {
+ return roles;
+ }
+
+ public void setRoles(String[] groups)
+ {
+ this.roles = groups;
+ }
+
+ public void clearPassword()
+ {
+ if (credential != null)
+ {
+ credential = null;
+ }
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionCachingAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionCachingAuthenticator.java
new file mode 100644
index 0000000000..b862fd8efe
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionCachingAuthenticator.java
@@ -0,0 +1,59 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.Authenticator;
+import org.eclipse.jetty.security.DefaultAuthentication;
+import org.eclipse.jetty.security.ServerAuthException;
+
+/**
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class SessionCachingAuthenticator extends DelegateAuthenticator
+{
+ public final static String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth";
+
+
+ public SessionCachingAuthenticator(Authenticator delegate)
+ {
+ super(delegate);
+ }
+
+ public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
+ {
+ HttpSession session = ((HttpServletRequest)request).getSession(mandatory);
+ // not mandatory and not authenticated
+ if (session == null)
+ return DefaultAuthentication.SUCCESS_UNAUTH_RESULTS;
+
+ Authentication authentication = (Authentication) session.getAttribute(__J_AUTHENTICATED);
+ if (authentication != null)
+ return authentication;
+
+ authentication = _delegate.validateRequest(request, response, mandatory);
+ if (authentication != null && authentication.getUserIdentity().getSubject() != null)
+ {
+ Authentication next=new DefaultAuthentication(Authentication.Status.SUCCESS,authentication.getAuthMethod(),authentication.getUserIdentity());
+ session.setAttribute(__J_AUTHENTICATED, next);
+ }
+ return authentication;
+ }
+
+}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/XCPSCachingAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/XCPSCachingAuthenticator.java
new file mode 100644
index 0000000000..c139bb45f1
--- /dev/null
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/XCPSCachingAuthenticator.java
@@ -0,0 +1,55 @@
+// ========================================================================
+// Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.security.Authentication;
+import org.eclipse.jetty.security.Authenticator;
+import org.eclipse.jetty.security.CrossContextPsuedoSession;
+import org.eclipse.jetty.security.ServerAuthException;
+
+/**
+ * Cross-context psuedo-session caching ServerAuthentication
+ *
+ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
+ */
+public class XCPSCachingAuthenticator extends DelegateAuthenticator
+{
+ public final static String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth";
+
+ private final CrossContextPsuedoSession<Authentication> _xcps;
+
+ public XCPSCachingAuthenticator(Authenticator delegate, CrossContextPsuedoSession<Authentication> xcps)
+ {
+ super(delegate);
+ this._xcps = xcps;
+ }
+
+ public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean manditory) throws ServerAuthException
+ {
+
+ Authentication serverAuthResult = _xcps.fetch((HttpServletRequest)request);
+ if (serverAuthResult != null) return serverAuthResult;
+
+ serverAuthResult = _delegate.validateRequest(request, response, manditory);
+ if (serverAuthResult != null) _xcps.store(serverAuthResult, (HttpServletResponse)response);
+
+ return serverAuthResult;
+ }
+
+}

Back to the top