diff options
author | Joakim Erdfelt | 2013-09-16 16:11:43 +0000 |
---|---|---|
committer | Joakim Erdfelt | 2013-09-16 16:11:43 +0000 |
commit | a71dce39ca8fd184bb9de9c60af687d34a88f75d (patch) | |
tree | 11a2e090c97d7b0741cc91cde50b53c42de44477 /jetty-plus/src/main/java/org/eclipse/jetty | |
parent | ea22c2128106dd1590210ef44064a2bfa1514848 (diff) | |
download | org.eclipse.jetty.project-a71dce39ca8fd184bb9de9c60af687d34a88f75d.tar.gz org.eclipse.jetty.project-a71dce39ca8fd184bb9de9c60af687d34a88f75d.tar.xz org.eclipse.jetty.project-a71dce39ca8fd184bb9de9c60af687d34a88f75d.zip |
Reverting to 2629f933973da2c50de65e0afd3f38eb7324f411
Diffstat (limited to 'jetty-plus/src/main/java/org/eclipse/jetty')
30 files changed, 2990 insertions, 484 deletions
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java deleted file mode 100644 index 9d93203c92..0000000000 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java +++ /dev/null @@ -1,113 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2013 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.plus.annotation; - -import java.util.HashSet; -import java.util.Set; - -import javax.servlet.ServletContainerInitializer; - -import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.webapp.WebAppContext; - -public class ContainerInitializer -{ - protected ServletContainerInitializer _target; - protected Class[] _interestedTypes; - protected Set<String> _applicableTypeNames; - protected Set<String> _annotatedTypeNames; - - - public void setTarget (ServletContainerInitializer target) - { - _target = target; - } - - public ServletContainerInitializer getTarget () - { - return _target; - } - - public Class[] getInterestedTypes () - { - return _interestedTypes; - } - - public void setInterestedTypes (Class[] interestedTypes) - { - _interestedTypes = interestedTypes; - } - - /** - * A class has been found that has an annotation of interest - * to this initializer. - * @param className - */ - public void addAnnotatedTypeName (String className) - { - if (_annotatedTypeNames == null) - _annotatedTypeNames = new HashSet<String>(); - _annotatedTypeNames.add(className); - } - - public Set<String> getAnnotatedTypeNames () - { - return _annotatedTypeNames; - } - - public void addApplicableTypeName (String className) - { - if (_applicableTypeNames == null) - _applicableTypeNames = new HashSet<String>(); - _applicableTypeNames.add(className); - } - - public Set<String> getApplicableTypeNames () - { - return _applicableTypeNames; - } - - - public void callStartup(WebAppContext context) - throws Exception - { - if (_target != null) - { - Set<Class<?>> classes = new HashSet<Class<?>>(); - - ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(context.getClassLoader()); - - try - { - if (_applicableTypeNames != null) - { - for (String s : _applicableTypeNames) - classes.add(Loader.loadClass(context.getClass(), s)); - } - - _target.onStartup(classes, context.getServletContext()); - } - finally - { - Thread.currentThread().setContextClassLoader(oldLoader); - } - } - } -} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java index df5c4bf4bc..d9b7a8ed2f 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java @@ -49,11 +49,11 @@ public class Injection private Class<?> _paramClass; private Class<?> _resourceClass; - + public Injection () { } - + /** * @return the _className @@ -67,22 +67,22 @@ public class Injection { return _paramClass; } - + public Class<?> getResourceClass () { return _resourceClass; } - + public boolean isField () { return (_target != null && _target instanceof Field); } - + public boolean isMethod () { return (_target != null && _target instanceof Method); } - + /** * @return the jndiName */ @@ -111,7 +111,7 @@ public class Injection { this._mappingName = mappingName; } - + /** * @return the target */ @@ -119,7 +119,7 @@ public class Injection { return _target; } - + public void setTarget(Class<?> clazz, Field field, Class<?> resourceType) { @@ -127,7 +127,7 @@ public class Injection _target = field; _resourceClass = resourceType; } - + public void setTarget(Class<?> clazz, Method method, Class<?> arg, Class<?> resourceType) { _targetClass = clazz; @@ -135,12 +135,12 @@ public class Injection _resourceClass = resourceType; _paramClass = arg; } - + public void setTarget (Class<?> clazz, String target, Class<?> resourceType) { _targetClass = clazz; _resourceClass = resourceType; - + //first look for a javabeans style setter matching the targetName String setter = "set"+target.substring(0,1).toUpperCase(Locale.ENGLISH)+target.substring(1); try @@ -165,13 +165,13 @@ public class Injection } } - + /** * Inject a value for a Resource from JNDI into an object * @param injectable */ public void inject (Object injectable) - { + { if (_target != null) { if (_target instanceof Field) @@ -183,7 +183,7 @@ public class Injection throw new IllegalStateException ("No method or field to inject with "+getJndiName()); } - + /** * The Resource must already exist in the ENC of this webapp. * @return the injected valud @@ -195,7 +195,7 @@ public class Injection InitialContext context = new InitialContext(); return context.lookup("java:comp/env/"+getJndiName()); } - + /** @@ -204,7 +204,7 @@ public class Injection * @param injectable */ protected void injectField (Field field, Object injectable) - { + { try { boolean accessibility = field.isAccessible(); @@ -239,5 +239,5 @@ public class Injection throw new IllegalStateException("Inject failed for method "+method.getName()); } } - + } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java index a45e83509d..6dac2d0e82 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java @@ -24,7 +24,6 @@ import java.lang.reflect.Modifier; import org.eclipse.jetty.util.IntrospectionUtil; import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.TypeUtil; @@ -40,8 +39,8 @@ public abstract class LifeCycleCallback private Class<?> _targetClass; private String _className; private String _methodName; - - + + public LifeCycleCallback() { } @@ -54,17 +53,17 @@ public abstract class LifeCycleCallback { return _targetClass; } - + public String getTargetClassName() { return _className; } - + public String getMethodName() { return _methodName; } - + /** * @return the target */ @@ -72,8 +71,8 @@ public abstract class LifeCycleCallback { return _target; } - - + + public void setTarget (String className, String methodName) { _className = className; @@ -98,18 +97,18 @@ public abstract class LifeCycleCallback } - - - public void callback (Object instance) + + + public void callback (Object instance) throws SecurityException, NoSuchMethodException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (_target == null) { if (_targetClass == null) _targetClass = Loader.loadClass(null, _className); - _target = _targetClass.getDeclaredMethod(_methodName, TypeUtil.NO_ARGS); + _target = _targetClass.getDeclaredMethod(_methodName, new Class[]{}); //TODO } - + if (_target != null) { boolean accessibility = getTarget().isAccessible(); @@ -119,15 +118,15 @@ public abstract class LifeCycleCallback } } - + /** * Find a method of the given name either directly in the given * class, or inherited. - * + * * @param pack the package of the class under inspection * @param clazz the class under inspection - * @param methodName the method to find + * @param methodName the method to find * @param checkInheritance false on first entry, true if a superclass is being introspected * @return the method */ @@ -138,7 +137,7 @@ public abstract class LifeCycleCallback try { - Method method = clazz.getDeclaredMethod(methodName); + Method method = clazz.getDeclaredMethod(methodName, null); if (checkInheritance) { int modifiers = method.getModifiers(); @@ -162,7 +161,7 @@ public abstract class LifeCycleCallback if (!(o instanceof LifeCycleCallback)) return false; LifeCycleCallback callback = (LifeCycleCallback)o; - + if (callback.getTargetClass()==null) { if (getTargetClass() != null) @@ -177,9 +176,9 @@ public abstract class LifeCycleCallback } else if (!callback.getTarget().equals(getTarget())) return false; - + return true; } - + public abstract void validate (Class<?> clazz, Method m); } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java index b43ca8666d..df8e3481b2 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java @@ -38,14 +38,14 @@ public class RunAsCollection public static final String RUNAS_COLLECTION = "org.eclipse.jetty.runAsCollection"; private HashMap<String, RunAs> _runAsMap = new HashMap<String, RunAs>();//map of classname to run-as - - - + + + public void add (RunAs runAs) { - if ((runAs==null) || (runAs.getTargetClassName()==null)) + if ((runAs==null) || (runAs.getTargetClassName()==null)) return; - + if (LOG.isDebugEnabled()) LOG.debug("Adding run-as for class="+runAs.getTargetClassName()); _runAsMap.put(runAs.getTargetClassName(), runAs); @@ -56,23 +56,23 @@ public class RunAsCollection { if (o==null) return null; - + return (RunAs)_runAsMap.get(o.getClass().getCanonicalName()); } - + public void setRunAs(Object o) throws ServletException { if (o == null) return; - + if (!ServletHolder.class.isAssignableFrom(o.getClass())) return; - + RunAs runAs = (RunAs)_runAsMap.get(o.getClass().getName()); if (runAs == null) return; - + runAs.setRunAs((ServletHolder)o); } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java new file mode 100644 index 0000000000..5310f4afa1 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASGroup.java @@ -0,0 +1,152 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas; + +import java.security.Principal; +import java.security.acl.Group; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; + + +public class JAASGroup implements Group +{ + public static final String ROLES = "__roles__"; + + private String _name = null; + private HashSet<Principal> _members = null; + + + + public JAASGroup(String n) + { + this._name = n; + this._members = new HashSet<Principal>(); + } + + /* ------------------------------------------------------------ */ + /** + * + * @param principal <description> + * @return <description> + */ + public synchronized boolean addMember(Principal principal) + { + return _members.add(principal); + } + + /** + * + * @param principal <description> + * @return <description> + */ + public synchronized boolean removeMember(Principal principal) + { + return _members.remove(principal); + } + + /** + * + * @param principal <description> + * @return <description> + */ + public boolean isMember(Principal principal) + { + return _members.contains(principal); + } + + + + /** + * + * @return <description> + */ + public Enumeration<? extends Principal> members() + { + + class MembersEnumeration implements Enumeration<Principal> + { + private Iterator<? extends Principal> itor; + + public MembersEnumeration (Iterator<? extends Principal> itor) + { + this.itor = itor; + } + + public boolean hasMoreElements () + { + return this.itor.hasNext(); + } + + + public Principal nextElement () + { + return this.itor.next(); + } + + } + + return new MembersEnumeration (_members.iterator()); + } + + + /** + * + * @return <description> + */ + public int hashCode() + { + return getName().hashCode(); + } + + + + /** + * + * @param object <description> + * @return <description> + */ + public boolean equals(Object object) + { + if (! (object instanceof JAASGroup)) + return false; + + return ((JAASGroup)object).getName().equals(getName()); + } + + /** + * + * @return <description> + */ + public String toString() + { + return getName(); + } + + /** + * + * @return <description> + */ + public String getName() + { + + return _name; + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java new file mode 100644 index 0000000000..b130d82470 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASLoginService.java @@ -0,0 +1,336 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas; + +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; +import org.eclipse.jetty.plus.jaas.callback.RequestParameterCallback; +import org.eclipse.jetty.security.DefaultIdentityService; +import org.eclipse.jetty.security.IdentityService; +import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.server.AbstractHttpConnection; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/* ---------------------------------------------------- */ +/** JAASLoginService + * + * @org.apache.xbean.XBean element="jaasUserRealm" description="Creates a UserRealm suitable for use with JAAS" + */ +public class JAASLoginService extends AbstractLifeCycle implements LoginService +{ + private static final Logger LOG = Log.getLogger(JAASLoginService.class); + + public static String DEFAULT_ROLE_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASRole"; + public static String[] DEFAULT_ROLE_CLASS_NAMES = {DEFAULT_ROLE_CLASS_NAME}; + + protected String[] _roleClassNames = DEFAULT_ROLE_CLASS_NAMES; + protected String _callbackHandlerClass; + protected String _realmName; + protected String _loginModuleName; + protected JAASUserPrincipal _defaultUser = new JAASUserPrincipal(null, null, null); + protected IdentityService _identityService; + + /* ---------------------------------------------------- */ + /** + * Constructor. + * + */ + public JAASLoginService() + { + } + + + /* ---------------------------------------------------- */ + /** + * Constructor. + * + * @param name the name of the realm + */ + public JAASLoginService(String name) + { + this(); + _realmName = name; + _loginModuleName = name; + } + + + /* ---------------------------------------------------- */ + /** + * Get the name of the realm. + * + * @return name or null if not set. + */ + public String getName() + { + return _realmName; + } + + + /* ---------------------------------------------------- */ + /** + * Set the name of the realm + * + * @param name a <code>String</code> value + */ + public void setName (String name) + { + _realmName = name; + } + + /* ------------------------------------------------------------ */ + /** Get the identityService. + * @return the identityService + */ + public IdentityService getIdentityService() + { + return _identityService; + } + + /* ------------------------------------------------------------ */ + /** Set the identityService. + * @param identityService the identityService to set + */ + public void setIdentityService(IdentityService identityService) + { + _identityService = identityService; + } + + /* ------------------------------------------------------------ */ + /** + * Set the name to use to index into the config + * file of LoginModules. + * + * @param name a <code>String</code> value + */ + public void setLoginModuleName (String name) + { + _loginModuleName = name; + } + + /* ------------------------------------------------------------ */ + public void setCallbackHandlerClass (String classname) + { + _callbackHandlerClass = classname; + } + + /* ------------------------------------------------------------ */ + public void setRoleClassNames (String[] classnames) + { + ArrayList<String> tmp = new ArrayList<String>(); + + if (classnames != null) + tmp.addAll(Arrays.asList(classnames)); + + if (!tmp.contains(DEFAULT_ROLE_CLASS_NAME)) + tmp.add(DEFAULT_ROLE_CLASS_NAME); + _roleClassNames = tmp.toArray(new String[tmp.size()]); + } + + /* ------------------------------------------------------------ */ + public String[] getRoleClassNames() + { + return _roleClassNames; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() + */ + protected void doStart() throws Exception + { + if (_identityService==null) + _identityService=new DefaultIdentityService(); + super.doStart(); + } + + /* ------------------------------------------------------------ */ + public UserIdentity login(final String username,final Object credentials) + { + try + { + CallbackHandler callbackHandler = null; + + + if (_callbackHandlerClass == null) + { + callbackHandler = new CallbackHandler() + { + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (Callback callback: callbacks) + { + if (callback instanceof NameCallback) + { + ((NameCallback)callback).setName(username); + } + else if (callback instanceof PasswordCallback) + { + ((PasswordCallback)callback).setPassword((char[]) credentials.toString().toCharArray()); + } + else if (callback instanceof ObjectCallback) + { + ((ObjectCallback)callback).setObject(credentials); + } + else if (callback instanceof RequestParameterCallback) + { + AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection(); + Request request = (connection == null? null : connection.getRequest()); + + if (request != null) + { + RequestParameterCallback rpc = (RequestParameterCallback)callback; + rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName()))); + } + } + else + throw new UnsupportedCallbackException(callback); + } + } + }; + } + else + { + Class clazz = Loader.loadClass(getClass(), _callbackHandlerClass); + callbackHandler = (CallbackHandler)clazz.newInstance(); + } + //set up the login context + //TODO jaspi requires we provide the Configuration parameter + Subject subject = new Subject(); + LoginContext loginContext = new LoginContext(_loginModuleName, subject, callbackHandler); + + loginContext.login(); + + //login success + JAASUserPrincipal userPrincipal = new JAASUserPrincipal(getUserName(callbackHandler), subject, loginContext); + subject.getPrincipals().add(userPrincipal); + + return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject)); + } + catch (LoginException e) + { + LOG.debug(e); + } + catch (IOException e) + { + LOG.info(e.getMessage()); + LOG.debug(e); + } + catch (UnsupportedCallbackException e) + { + LOG.info(e.getMessage()); + LOG.debug(e); + } + catch (InstantiationException e) + { + LOG.info(e.getMessage()); + LOG.debug(e); + } + catch (IllegalAccessException e) + { + LOG.info(e.getMessage()); + LOG.debug(e); + } + catch (ClassNotFoundException e) + { + LOG.info(e.getMessage()); + LOG.debug(e); + } + return null; + } + + /* ------------------------------------------------------------ */ + public boolean validate(UserIdentity user) + { + // TODO optionally check user is still valid + return true; + } + + /* ------------------------------------------------------------ */ + private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException + { + NameCallback nameCallback = new NameCallback("foo"); + callbackHandler.handle(new Callback[] {nameCallback}); + return nameCallback.getName(); + } + + /* ------------------------------------------------------------ */ + public void logout(UserIdentity user) + { + Set<JAASUserPrincipal> userPrincipals = user.getSubject().getPrincipals(JAASUserPrincipal.class); + LoginContext loginContext = userPrincipals.iterator().next().getLoginContext(); + try + { + loginContext.logout(); + } + catch (LoginException e) + { + LOG.warn(e); + } + } + + + /* ------------------------------------------------------------ */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private String[] getGroups (Subject subject) + { + //get all the roles of the various types + String[] roleClassNames = getRoleClassNames(); + Collection<String> groups = new LinkedHashSet<String>(); + try + { + for (String roleClassName : roleClassNames) + { + Class load_class = Thread.currentThread().getContextClassLoader().loadClass(roleClassName); + Set<Principal> rolesForType = subject.getPrincipals(load_class); + for (Principal principal : rolesForType) + { + groups.add(principal.getName()); + } + } + + return groups.toArray(new String[groups.size()]); + } + catch (ClassNotFoundException e) + { + throw new RuntimeException(e); + } + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java new file mode 100644 index 0000000000..6aa158cf36 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASPrincipal.java @@ -0,0 +1,89 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas; + +import java.io.Serializable; +import java.security.Principal; + + + +/* ---------------------------------------------------- */ +/** JAASPrincipal + * <p>Impl class of Principal interface. + * + * <p><h4>Notes</h4> + * <p> + * + * <p><h4>Usage</h4> + * <pre> + */ +/* + * </pre> + * + * @see + * @version 1.0 Tue Apr 15 2003 + * + */ +public class JAASPrincipal implements Principal, Serializable +{ + /** + * + */ + private static final long serialVersionUID = -5538962177019315479L; + + private String _name = null; + + + public JAASPrincipal(String userName) + { + this._name = userName; + } + + + public boolean equals (Object p) + { + if (! (p instanceof JAASPrincipal)) + return false; + + return getName().equals(((JAASPrincipal)p).getName()); + } + + + public int hashCode () + { + return getName().hashCode(); + } + + + public String getName () + { + return this._name; + } + + + public String toString () + { + return getName(); + } + + + +} + + diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/package-info.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASRole.java index dae277ef35..d29b1af8f7 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/package-info.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASRole.java @@ -16,8 +16,27 @@ // ======================================================================== // -/** - * Jetty Plus : Limited Additional JEE Webapp Support - */ -package org.eclipse.jetty.plus.webapp; +package org.eclipse.jetty.plus.jaas; + +public class JAASRole extends JAASPrincipal +{ + + /** + * + */ + private static final long serialVersionUID = 3465114254970134526L; + + public JAASRole(String name) + { + super (name); + } + + public boolean equals (Object o) + { + if (! (o instanceof JAASRole)) + return false; + + return getName().equals(((JAASRole)o).getName()); + } +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java new file mode 100644 index 0000000000..e2b4c5df32 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/JAASUserPrincipal.java @@ -0,0 +1,79 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas; + +import java.security.Principal; + +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; + + + +/* ---------------------------------------------------- */ +/** JAASUserPrincipal + * <p>Implements the JAAS version of the + * org.eclipse.jetty.http.UserPrincipal interface. + * + * @version $Id: JAASUserPrincipal.java 4780 2009-03-17 15:36:08Z jesse $ + * + */ +public class JAASUserPrincipal implements Principal +{ + private final String _name; + private final Subject _subject; + private final LoginContext _loginContext; + + /* ------------------------------------------------ */ + + public JAASUserPrincipal(String name, Subject subject, LoginContext loginContext) + { + this._name = name; + this._subject = subject; + this._loginContext = loginContext; + } + + /* ------------------------------------------------ */ + /** Get the name identifying the user + */ + public String getName () + { + return _name; + } + + + /* ------------------------------------------------ */ + /** Provide access to the Subject + * @return subject + */ + public Subject getSubject () + { + return this._subject; + } + + LoginContext getLoginContext () + { + return this._loginContext; + } + + public String toString() + { + return getName(); + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/package-info.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/RoleCheckPolicy.java index 2865c35471..ad99895d1e 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/package-info.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/RoleCheckPolicy.java @@ -16,8 +16,21 @@ // ======================================================================== // -/** - * Jetty Plus : Limited JEE Annotation Support - */ -package org.eclipse.jetty.plus.annotation; +package org.eclipse.jetty.plus.jaas; +import java.security.Principal; +import java.security.acl.Group; + + +public interface RoleCheckPolicy +{ + /* ------------------------------------------------ */ + /** Check if a role is either a runAsRole or in a set of roles + * @param roleName the role to check + * @param runAsRole a pushed role (can be null) + * @param roles a Group whose Principals are role names + * @return <code>true</code> if <code>role</code> equals <code>runAsRole</code> or is a member of <code>roles</code>. + */ + public boolean checkRole (String roleName, Principal runAsRole, Group roles); + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java new file mode 100644 index 0000000000..9da82eedc2 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/StrictRoleCheckPolicy.java @@ -0,0 +1,63 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas; + +import java.security.Principal; +import java.security.acl.Group; +import java.util.Enumeration; + + +/* ---------------------------------------------------- */ +/** StrictRoleCheckPolicy + * <p>Enforces that if a runAsRole is present, then the + * role to check must be the same as that runAsRole and + * the set of static roles is ignored. + * + * + * + * @org.apache.xbean.XBean description ="Check only topmost role in stack of roles for user" + */ +public class StrictRoleCheckPolicy implements RoleCheckPolicy +{ + + public boolean checkRole (String roleName, Principal runAsRole, Group roles) + { + //check if this user has had any temporary role pushed onto + //them. If so, then only check if the user has that role. + if (runAsRole != null) + { + return (roleName.equals(runAsRole.getName())); + } + else + { + if (roles == null) + return false; + Enumeration<? extends Principal> rolesEnum = roles.members(); + boolean found = false; + while (rolesEnum.hasMoreElements() && !found) + { + Principal p = (Principal)rolesEnum.nextElement(); + found = roleName.equals(p.getName()); + } + return found; + } + + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java new file mode 100644 index 0000000000..a5791a17ab --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/AbstractCallbackHandler.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.callback; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + + +public abstract class AbstractCallbackHandler implements CallbackHandler +{ + protected String _userName; + protected Object _credential; + + public void setUserName (String userName) + { + _userName = userName; + } + + public String getUserName () + { + return _userName; + } + + + public void setCredential (Object credential) + { + _credential = credential; + } + + public Object getCredential () + { + return _credential; + } + + public void handle (Callback[] callbacks) + throws IOException, UnsupportedCallbackException + { + } + + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java new file mode 100644 index 0000000000..6c6580c4ee --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/DefaultCallbackHandler.java @@ -0,0 +1,97 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.callback; + +import java.io.IOException; +import java.util.Arrays; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.server.Request; + + + +/* ---------------------------------------------------- */ +/** DefaultUsernameCredentialCallbackHandler + * <p> + * + * <p><h4>Notes</h4> + * <p> + * + * <p><h4>Usage</h4> + * <pre> + */ +/* + * </pre> + * + * @see + * @version 1.0 Tue Apr 15 2003 + * + */ +public class DefaultCallbackHandler extends AbstractCallbackHandler +{ + + private Request _request; + + public void setRequest (Request request) + { + this._request = request; + } + + public void handle (Callback[] callbacks) + throws IOException, UnsupportedCallbackException + { + for (int i=0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + ((NameCallback)callbacks[i]).setName(getUserName()); + } + else if (callbacks[i] instanceof ObjectCallback) + { + ((ObjectCallback)callbacks[i]).setObject(getCredential()); + } + else if (callbacks[i] instanceof PasswordCallback) + { + if (getCredential() instanceof Password) + ((PasswordCallback)callbacks[i]).setPassword (((Password)getCredential()).toString().toCharArray()); + else if (getCredential() instanceof String) + { + ((PasswordCallback)callbacks[i]).setPassword (((String)getCredential()).toCharArray()); + } + else + throw new UnsupportedCallbackException (callbacks[i], "User supplied credentials cannot be converted to char[] for PasswordCallback: try using an ObjectCallback instead"); + } + else if (callbacks[i] instanceof RequestParameterCallback) + { + RequestParameterCallback callback = (RequestParameterCallback)callbacks[i]; + callback.setParameterValues(Arrays.asList(_request.getParameterValues(callback.getParameterName()))); + } + else + throw new UnsupportedCallbackException(callbacks[i]); + } + + } + +} + diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/package-info.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/ObjectCallback.java index b3d3c14838..6a49d9ae13 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/package-info.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/ObjectCallback.java @@ -16,8 +16,52 @@ // ======================================================================== // -/** - * Jetty Plus : Limited JEE Jndi Support +package org.eclipse.jetty.plus.jaas.callback; + +import javax.security.auth.callback.Callback; + + +/* ---------------------------------------------------- */ +/** ObjectCallback + * + * <p>Can be used as a LoginModule Callback to + * obtain a user's credential as an Object, rather than + * a char[], to which some credentials may not be able + * to be converted + * + * <p><h4>Notes</h4> + * <p> + * + * <p><h4>Usage</h4> + * <pre> + */ +/* + * </pre> + * + * @see + * @version 1.0 Tue Apr 15 2003 + * */ -package org.eclipse.jetty.plus.jndi; +public class ObjectCallback implements Callback +{ + + protected Object _object; + + public void setObject(Object o) + { + _object = o; + } + + public Object getObject () + { + return _object; + } + + public void clearObject () + { + _object = null; + } + + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java new file mode 100644 index 0000000000..3129983384 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/callback/RequestParameterCallback.java @@ -0,0 +1,61 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.callback; + +import java.util.List; + +import javax.security.auth.callback.Callback; + + +/** + * + * RequestParameterCallback + * + * Allows a JAAS callback handler to access any parameter from the j_security_check FORM. + * This means that a LoginModule can access form fields other than the j_username and j_password + * fields, and use it, for example, to authenticate a user. + * + * + * @version $Revision: 4780 $ $Date: 2009-03-17 16:36:08 +0100 (Tue, 17 Mar 2009) $ + * + */ +public class RequestParameterCallback implements Callback +{ + private String _paramName; + private List<?> _paramValues; + + public void setParameterName (String name) + { + _paramName = name; + } + public String getParameterName () + { + return _paramName; + } + + public void setParameterValues (List<?> values) + { + _paramValues = values; + } + + public List<?> getParameterValues () + { + return _paramValues; + } +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java new file mode 100644 index 0000000000..dc48576518 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractDatabaseLoginModule.java @@ -0,0 +1,144 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; + +import org.eclipse.jetty.util.security.Credential; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * AbstractDatabaseLoginModule + * + * Abstract base class for LoginModules that interact with a + * database to retrieve authentication and authorization information. + * Used by the JDBCLoginModule and DataSourceLoginModule. + * + */ +public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule +{ + private static final Logger LOG = Log.getLogger(AbstractDatabaseLoginModule.class); + + private String userQuery; + private String rolesQuery; + private String dbUserTable; + private String dbUserTableUserField; + private String dbUserTableCredentialField; + private String dbUserRoleTable; + private String dbUserRoleTableUserField; + private String dbUserRoleTableRoleField; + + + + + /** + * @return a java.sql.Connection from the database + * @throws Exception + */ + public abstract Connection getConnection () throws Exception; + + + + /* ------------------------------------------------ */ + /** Load info from database + * @param userName user info to load + * @exception SQLException + */ + public UserInfo getUserInfo (String userName) + throws Exception + { + Connection connection = null; + + try + { + connection = getConnection(); + + //query for credential + PreparedStatement statement = connection.prepareStatement (userQuery); + statement.setString (1, userName); + ResultSet results = statement.executeQuery(); + String dbCredential = null; + if (results.next()) + { + dbCredential = results.getString(1); + } + results.close(); + statement.close(); + + //query for role names + statement = connection.prepareStatement (rolesQuery); + statement.setString (1, userName); + results = statement.executeQuery(); + List<String> roles = new ArrayList<String>(); + + while (results.next()) + { + String roleName = results.getString (1); + roles.add (roleName); + } + + results.close(); + statement.close(); + + return dbCredential==null ? null : new UserInfo (userName, + Credential.getCredential(dbCredential), roles); + } + finally + { + if (connection != null) connection.close(); + } + } + + + public void initialize(Subject subject, + CallbackHandler callbackHandler, + Map<String,?> sharedState, + Map<String,?> options) + { + super.initialize(subject, callbackHandler, sharedState, options); + + //get the user credential query out of the options + dbUserTable = (String)options.get("userTable"); + dbUserTableUserField = (String)options.get("userField"); + dbUserTableCredentialField = (String)options.get("credentialField"); + + userQuery = "select "+dbUserTableCredentialField+" from "+dbUserTable+" where "+dbUserTableUserField+"=?"; + + + //get the user roles query out of the options + dbUserRoleTable = (String)options.get("userRoleTable"); + dbUserRoleTableUserField = (String)options.get("userRoleUserField"); + dbUserRoleTableRoleField = (String)options.get("userRoleRoleField"); + + rolesQuery = "select "+dbUserRoleTableRoleField+" from "+dbUserRoleTable+" where "+dbUserRoleTableUserField+"=?"; + + if(LOG.isDebugEnabled())LOG.debug("userQuery = "+userQuery); + if(LOG.isDebugEnabled())LOG.debug("rolesQuery = "+rolesQuery); + } +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java new file mode 100644 index 0000000000..f22258e2a0 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java @@ -0,0 +1,289 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.eclipse.jetty.plus.jaas.JAASPrincipal; +import org.eclipse.jetty.plus.jaas.JAASRole; +import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; + +/** + * AbstractLoginModule + * + * Abstract base class for all LoginModules. Subclasses should + * just need to implement getUserInfo method. + * + */ +public abstract class AbstractLoginModule implements LoginModule +{ + private CallbackHandler callbackHandler; + + private boolean authState = false; + private boolean commitState = false; + private JAASUserInfo currentUser; + private Subject subject; + + public class JAASUserInfo + { + private UserInfo user; + private Principal principal; + private List<JAASRole> roles; + + public JAASUserInfo (UserInfo u) + { + setUserInfo(u); + } + + public String getUserName () + { + return this.user.getUserName(); + } + + public Principal getPrincipal() + { + return this.principal; + } + + public void setUserInfo (UserInfo u) + { + this.user = u; + this.principal = new JAASPrincipal(u.getUserName()); + this.roles = new ArrayList<JAASRole>(); + if (u.getRoleNames() != null) + { + Iterator<String> itor = u.getRoleNames().iterator(); + while (itor.hasNext()) + this.roles.add(new JAASRole((String)itor.next())); + } + } + + public void setJAASInfo (Subject subject) + { + subject.getPrincipals().add(this.principal); + subject.getPrivateCredentials().add(this.user.getCredential()); + subject.getPrincipals().addAll(roles); + } + + public void unsetJAASInfo (Subject subject) + { + subject.getPrincipals().remove(this.principal); + subject.getPrivateCredentials().remove(this.user.getCredential()); + subject.getPrincipals().removeAll(this.roles); + } + + public boolean checkCredential (Object suppliedCredential) + { + return this.user.checkCredential(suppliedCredential); + } + } + + + + public Subject getSubject () + { + return this.subject; + } + + public void setSubject (Subject s) + { + this.subject = s; + } + + public JAASUserInfo getCurrentUser() + { + return this.currentUser; + } + + public void setCurrentUser (JAASUserInfo u) + { + this.currentUser = u; + } + + public CallbackHandler getCallbackHandler() + { + return this.callbackHandler; + } + + public void setCallbackHandler(CallbackHandler h) + { + this.callbackHandler = h; + } + + public boolean isAuthenticated() + { + return this.authState; + } + + public boolean isCommitted () + { + return this.commitState; + } + + public void setAuthenticated (boolean authState) + { + this.authState = authState; + } + + public void setCommitted (boolean commitState) + { + this.commitState = commitState; + } + /** + * @see javax.security.auth.spi.LoginModule#abort() + * @throws LoginException + */ + public boolean abort() throws LoginException + { + this.currentUser = null; + return (isAuthenticated() && isCommitted()); + } + + /** + * @see javax.security.auth.spi.LoginModule#commit() + * @return true if committed, false if not (likely not authenticated) + * @throws LoginException + */ + public boolean commit() throws LoginException + { + + if (!isAuthenticated()) + { + currentUser = null; + setCommitted(false); + return false; + } + + setCommitted(true); + currentUser.setJAASInfo(subject); + return true; + } + + + public Callback[] configureCallbacks () + { + + Callback[] callbacks = new Callback[3]; + callbacks[0] = new NameCallback("Enter user name"); + callbacks[1] = new ObjectCallback(); + callbacks[2] = new PasswordCallback("Enter password", false); //only used if framework does not support the ObjectCallback + return callbacks; + } + + + + public abstract UserInfo getUserInfo (String username) throws Exception; + + + + /** + * @see javax.security.auth.spi.LoginModule#login() + * @return true if is authenticated, false otherwise + * @throws LoginException + */ + public boolean login() throws LoginException + { + try + { + if (callbackHandler == null) + throw new LoginException ("No callback handler"); + + Callback[] callbacks = configureCallbacks(); + callbackHandler.handle(callbacks); + + String webUserName = ((NameCallback)callbacks[0]).getName(); + Object webCredential = null; + + webCredential = ((ObjectCallback)callbacks[1]).getObject(); //first check if ObjectCallback has the credential + if (webCredential == null) + webCredential = ((PasswordCallback)callbacks[2]).getPassword(); //use standard PasswordCallback + + if ((webUserName == null) || (webCredential == null)) + { + setAuthenticated(false); + return isAuthenticated(); + } + + UserInfo userInfo = getUserInfo(webUserName); + + if (userInfo == null) + { + setAuthenticated(false); + return isAuthenticated(); + } + + currentUser = new JAASUserInfo(userInfo); + setAuthenticated(currentUser.checkCredential(webCredential)); + return isAuthenticated(); + } + catch (IOException e) + { + throw new LoginException (e.toString()); + } + catch (UnsupportedCallbackException e) + { + throw new LoginException (e.toString()); + } + catch (Exception e) + { + e.printStackTrace(); + throw new LoginException (e.toString()); + } + } + + /** + * @see javax.security.auth.spi.LoginModule#logout() + * @return true always + * @throws LoginException + */ + public boolean logout() throws LoginException + { + this.currentUser.unsetJAASInfo(this.subject); + return true; + } + + /** + * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map) + * @param subject + * @param callbackHandler + * @param sharedState + * @param options + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map<String,?> sharedState, Map<String,?> options) + { + this.callbackHandler = callbackHandler; + this.subject = subject; + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java new file mode 100644 index 0000000000..303e5d44f8 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java @@ -0,0 +1,89 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; +import java.sql.Connection; +import java.util.Map; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.sql.DataSource; + +/** + * DataSourceLoginModule + * + * A LoginModule that uses a DataSource to retrieve user authentication + * and authorisation information. + * + * @see JDBCLoginModule + */ +public class DataSourceLoginModule extends AbstractDatabaseLoginModule +{ + + private String dbJNDIName; + private DataSource dataSource; + + /* ------------------------------------------------ */ + /** Init LoginModule. + * Called once by JAAS after new instance created. + * @param subject + * @param callbackHandler + * @param sharedState + * @param options + */ + public void initialize(Subject subject, + CallbackHandler callbackHandler, + Map<String,?> sharedState, + Map<String,?> options) + { + try + { + super.initialize(subject, callbackHandler, sharedState, options); + + //get the datasource jndi name + dbJNDIName = (String)options.get("dbJNDIName"); + + InitialContext ic = new InitialContext(); + dataSource = (DataSource)ic.lookup("java:comp/env/"+dbJNDIName); + } + catch (NamingException e) + { + throw new IllegalStateException (e.toString()); + } + } + + + /** + * Get a connection from the DataSource + * @see AbstractDatabaseLoginModule#getConnection() + * @return the connection for the datasource + * @throws Exception + */ + public Connection getConnection () + throws Exception + { + return dataSource.getConnection(); + } + + + + + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java new file mode 100644 index 0000000000..4243636105 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java @@ -0,0 +1,127 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; + +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + + +/* ---------------------------------------------------- */ +/** JDBCLoginModule + * <p>JAAS LoginModule to retrieve user information from + * a database and authenticate the user. + * + * <p><h4>Notes</h4> + * <p>This version uses plain old JDBC connections NOT + * Datasources. + * + * <p><h4>Usage</h4> + * <pre> + * </pre> + * + * @version 1.0 Tue Apr 15 2003 + */ +public class JDBCLoginModule extends AbstractDatabaseLoginModule +{ + private static final Logger LOG = Log.getLogger(JDBCLoginModule.class); + + private String dbDriver; + private String dbUrl; + private String dbUserName; + private String dbPassword; + + + /** + * Get a connection from the DriverManager + * @see AbstractDatabaseLoginModule#getConnection() + * @return the connection for this datasource + * @throws Exception + */ + public Connection getConnection () + throws Exception + { + if (!((dbDriver != null) + && + (dbUrl != null))) + throw new IllegalStateException ("Database connection information not configured"); + + if(LOG.isDebugEnabled())LOG.debug("Connecting using dbDriver="+dbDriver+"+ dbUserName="+dbUserName+", dbPassword="+dbUrl); + + return DriverManager.getConnection (dbUrl, + dbUserName, + dbPassword); + } + + + + /* ------------------------------------------------ */ + /** Init LoginModule. + * Called once by JAAS after new instance created. + * @param subject + * @param callbackHandler + * @param sharedState + * @param options + */ + public void initialize(Subject subject, + CallbackHandler callbackHandler, + Map<String,?> sharedState, + Map<String,?> options) + { + try + { + super.initialize(subject, callbackHandler, sharedState, options); + + //get the jdbc username/password, jdbc url out of the options + dbDriver = (String)options.get("dbDriver"); + dbUrl = (String)options.get("dbUrl"); + dbUserName = (String)options.get("dbUserName"); + dbPassword = (String)options.get("dbPassword"); + + if (dbUserName == null) + dbUserName = ""; + + if (dbPassword == null) + dbPassword = ""; + + if (dbDriver != null) + Loader.loadClass(this.getClass(), dbDriver).newInstance(); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException (e.toString()); + } + catch (InstantiationException e) + { + throw new IllegalStateException (e.toString()); + } + catch (IllegalAccessException e) + { + throw new IllegalStateException (e.toString()); + } + } +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java new file mode 100644 index 0000000000..584c1a4f0f --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java @@ -0,0 +1,689 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; + +import org.eclipse.jetty.util.security.Credential; +import org.eclipse.jetty.plus.jaas.callback.ObjectCallback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * A LdapLoginModule for use with JAAS setups + * <p/> + * The jvm should be started with the following parameter: + * <br><br> + * <code> + * -Djava.security.auth.login.config=etc/ldap-loginModule.conf + * </code> + * <br><br> + * and an example of the ldap-loginModule.conf would be: + * <br><br> + * <pre> + * ldaploginmodule { + * org.eclipse.jetty.server.server.plus.jaas.spi.LdapLoginModule required + * debug="true" + * useLdaps="false" + * contextFactory="com.sun.jndi.ldap.LdapCtxFactory" + * hostname="ldap.example.com" + * port="389" + * bindDn="cn=Directory Manager" + * bindPassword="directory" + * authenticationMethod="simple" + * forceBindingLogin="false" + * userBaseDn="ou=people,dc=alcatel" + * userRdnAttribute="uid" + * userIdAttribute="uid" + * userPasswordAttribute="userPassword" + * userObjectClass="inetOrgPerson" + * roleBaseDn="ou=groups,dc=example,dc=com" + * roleNameAttribute="cn" + * roleMemberAttribute="uniqueMember" + * roleObjectClass="groupOfUniqueNames"; + * }; + * </pre> + * + * + * + * + */ +public class LdapLoginModule extends AbstractLoginModule +{ + private static final Logger LOG = Log.getLogger(LdapLoginModule.class); + + /** + * hostname of the ldap server + */ + private String _hostname; + + /** + * port of the ldap server + */ + private int _port; + + /** + * Context.SECURITY_AUTHENTICATION + */ + private String _authenticationMethod; + + /** + * Context.INITIAL_CONTEXT_FACTORY + */ + private String _contextFactory; + + /** + * root DN used to connect to + */ + private String _bindDn; + + /** + * password used to connect to the root ldap context + */ + private String _bindPassword; + + /** + * object class of a user + */ + private String _userObjectClass = "inetOrgPerson"; + + /** + * attribute that the principal is located + */ + private String _userRdnAttribute = "uid"; + + /** + * attribute that the principal is located + */ + private String _userIdAttribute = "cn"; + + /** + * name of the attribute that a users password is stored under + * <p/> + * NOTE: not always accessible, see force binding login + */ + private String _userPasswordAttribute = "userPassword"; + + /** + * base DN where users are to be searched from + */ + private String _userBaseDn; + + /** + * base DN where role membership is to be searched from + */ + private String _roleBaseDn; + + /** + * object class of roles + */ + private String _roleObjectClass = "groupOfUniqueNames"; + + /** + * name of the attribute that a username would be under a role class + */ + private String _roleMemberAttribute = "uniqueMember"; + + /** + * the name of the attribute that a role would be stored under + */ + private String _roleNameAttribute = "roleName"; + + private boolean _debug; + + /** + * if the getUserInfo can pull a password off of the user then + * password comparison is an option for authn, to force binding + * login checks, set this to true + */ + private boolean _forceBindingLogin = false; + + /** + * When true changes the protocol to ldaps + */ + private boolean _useLdaps = false; + + private DirContext _rootContext; + + /** + * get the available information about the user + * <p/> + * for this LoginModule, the credential can be null which will result in a + * binding ldap authentication scenario + * <p/> + * roles are also an optional concept if required + * + * @param username + * @return the userinfo for the username + * @throws Exception + */ + public UserInfo getUserInfo(String username) throws Exception + { + String pwdCredential = getUserCredentials(username); + + if (pwdCredential == null) + { + return null; + } + + pwdCredential = convertCredentialLdapToJetty(pwdCredential); + Credential credential = Credential.getCredential(pwdCredential); + List<String> roles = getUserRoles(_rootContext, username); + + return new UserInfo(username, credential, roles); + } + + protected String doRFC2254Encoding(String inputString) + { + StringBuffer buf = new StringBuffer(inputString.length()); + for (int i = 0; i < inputString.length(); i++) + { + char c = inputString.charAt(i); + switch (c) + { + case '\\': + buf.append("\\5c"); + break; + case '*': + buf.append("\\2a"); + break; + case '(': + buf.append("\\28"); + break; + case ')': + buf.append("\\29"); + break; + case '\0': + buf.append("\\00"); + break; + default: + buf.append(c); + break; + } + } + return buf.toString(); + } + + /** + * attempts to get the users credentials from the users context + * <p/> + * NOTE: this is not an user authenticated operation + * + * @param username + * @return + * @throws LoginException + */ + private String getUserCredentials(String username) throws LoginException + { + String ldapCredential = null; + + SearchControls ctls = new SearchControls(); + ctls.setCountLimit(1); + ctls.setDerefLinkFlag(true); + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + String filter = "(&(objectClass={0})({1}={2}))"; + + LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn); + + try + { + Object[] filterArguments = {_userObjectClass, _userIdAttribute, username}; + NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls); + + LOG.debug("Found user?: " + results.hasMoreElements()); + + if (!results.hasMoreElements()) + { + throw new LoginException("User not found."); + } + + SearchResult result = findUser(username); + + Attributes attributes = result.getAttributes(); + + Attribute attribute = attributes.get(_userPasswordAttribute); + if (attribute != null) + { + try + { + byte[] value = (byte[]) attribute.get(); + + ldapCredential = new String(value); + } + catch (NamingException e) + { + LOG.debug("no password available under attribute: " + _userPasswordAttribute); + } + } + } + catch (NamingException e) + { + throw new LoginException("Root context binding failure."); + } + + LOG.debug("user cred is: " + ldapCredential); + + return ldapCredential; + } + + /** + * attempts to get the users roles from the root context + * <p/> + * NOTE: this is not an user authenticated operation + * + * @param dirContext + * @param username + * @return + * @throws LoginException + */ + private List<String> getUserRoles(DirContext dirContext, String username) throws LoginException, NamingException + { + String userDn = _userRdnAttribute + "=" + username + "," + _userBaseDn; + + return getUserRolesByDn(dirContext, userDn); + } + + private List<String> getUserRolesByDn(DirContext dirContext, String userDn) throws LoginException, NamingException + { + List<String> roleList = new ArrayList<String>(); + + if (dirContext == null || _roleBaseDn == null || _roleMemberAttribute == null || _roleObjectClass == null) + { + return roleList; + } + + SearchControls ctls = new SearchControls(); + ctls.setDerefLinkFlag(true); + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + ctls.setReturningAttributes(new String[]{_roleNameAttribute}); + + String filter = "(&(objectClass={0})({1}={2}))"; + Object[] filterArguments = {_roleObjectClass, _roleMemberAttribute, userDn}; + NamingEnumeration<SearchResult> results = dirContext.search(_roleBaseDn, filter, filterArguments, ctls); + + LOG.debug("Found user roles?: " + results.hasMoreElements()); + + while (results.hasMoreElements()) + { + SearchResult result = (SearchResult) results.nextElement(); + + Attributes attributes = result.getAttributes(); + + if (attributes == null) + { + continue; + } + + Attribute roleAttribute = attributes.get(_roleNameAttribute); + + if (roleAttribute == null) + { + continue; + } + + NamingEnumeration<?> roles = roleAttribute.getAll(); + while (roles.hasMore()) + { + roleList.add(roles.next().toString()); + } + } + + return roleList; + } + + + /** + * since ldap uses a context bind for valid authentication checking, we override login() + * <p/> + * if credentials are not available from the users context or if we are forcing the binding check + * then we try a binding authentication check, otherwise if we have the users encoded password then + * we can try authentication via that mechanic + * + * @return true if authenticated, false otherwise + * @throws LoginException + */ + public boolean login() throws LoginException + { + try + { + if (getCallbackHandler() == null) + { + throw new LoginException("No callback handler"); + } + + Callback[] callbacks = configureCallbacks(); + getCallbackHandler().handle(callbacks); + + String webUserName = ((NameCallback) callbacks[0]).getName(); + Object webCredential = ((ObjectCallback) callbacks[1]).getObject(); + + if (webUserName == null || webCredential == null) + { + setAuthenticated(false); + return isAuthenticated(); + } + + if (_forceBindingLogin) + { + return bindingLogin(webUserName, webCredential); + } + + // This sets read and the credential + UserInfo userInfo = getUserInfo(webUserName); + + if (userInfo == null) + { + setAuthenticated(false); + return false; + } + + setCurrentUser(new JAASUserInfo(userInfo)); + + if (webCredential instanceof String) + { + return credentialLogin(Credential.getCredential((String) webCredential)); + } + + return credentialLogin(webCredential); + } + catch (UnsupportedCallbackException e) + { + throw new LoginException("Error obtaining callback information."); + } + catch (IOException e) + { + if (_debug) + { + e.printStackTrace(); + } + throw new LoginException("IO Error performing login."); + } + catch (Exception e) + { + if (_debug) + { + e.printStackTrace(); + } + throw new LoginException("Error obtaining user info."); + } + } + + /** + * password supplied authentication check + * + * @param webCredential + * @return true if authenticated + * @throws LoginException + */ + protected boolean credentialLogin(Object webCredential) throws LoginException + { + setAuthenticated(getCurrentUser().checkCredential(webCredential)); + return isAuthenticated(); + } + + /** + * binding authentication check + * This method of authentication works only if the user branch of the DIT (ldap tree) + * has an ACI (access control instruction) that allow the access to any user or at least + * for the user that logs in. + * + * @param username + * @param password + * @return true always + * @throws LoginException + */ + public boolean bindingLogin(String username, Object password) throws LoginException, NamingException + { + SearchResult searchResult = findUser(username); + + String userDn = searchResult.getNameInNamespace(); + + LOG.info("Attempting authentication: " + userDn); + + Hashtable<Object,Object> environment = getEnvironment(); + environment.put(Context.SECURITY_PRINCIPAL, userDn); + environment.put(Context.SECURITY_CREDENTIALS, password); + + DirContext dirContext = new InitialDirContext(environment); + List<String> roles = getUserRolesByDn(dirContext, userDn); + + UserInfo userInfo = new UserInfo(username, null, roles); + setCurrentUser(new JAASUserInfo(userInfo)); + setAuthenticated(true); + + return true; + } + + private SearchResult findUser(String username) throws NamingException, LoginException + { + SearchControls ctls = new SearchControls(); + ctls.setCountLimit(1); + ctls.setDerefLinkFlag(true); + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + String filter = "(&(objectClass={0})({1}={2}))"; + + LOG.info("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn); + + Object[] filterArguments = new Object[]{ + _userObjectClass, + _userIdAttribute, + username + }; + NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls); + + LOG.info("Found user?: " + results.hasMoreElements()); + + if (!results.hasMoreElements()) + { + throw new LoginException("User not found."); + } + + return (SearchResult) results.nextElement(); + } + + + /** + * Init LoginModule. + * Called once by JAAS after new instance is created. + * + * @param subject + * @param callbackHandler + * @param sharedState + * @param options + */ + public void initialize(Subject subject, + CallbackHandler callbackHandler, + Map<String,?> sharedState, + Map<String,?> options) + { + super.initialize(subject, callbackHandler, sharedState, options); + + _hostname = (String) options.get("hostname"); + _port = Integer.parseInt((String) options.get("port")); + _contextFactory = (String) options.get("contextFactory"); + _bindDn = (String) options.get("bindDn"); + _bindPassword = (String) options.get("bindPassword"); + _authenticationMethod = (String) options.get("authenticationMethod"); + + _userBaseDn = (String) options.get("userBaseDn"); + + _roleBaseDn = (String) options.get("roleBaseDn"); + + if (options.containsKey("forceBindingLogin")) + { + _forceBindingLogin = Boolean.parseBoolean((String) options.get("forceBindingLogin")); + } + + if (options.containsKey("useLdaps")) + { + _useLdaps = Boolean.parseBoolean((String) options.get("useLdaps")); + } + + _userObjectClass = getOption(options, "userObjectClass", _userObjectClass); + _userRdnAttribute = getOption(options, "userRdnAttribute", _userRdnAttribute); + _userIdAttribute = getOption(options, "userIdAttribute", _userIdAttribute); + _userPasswordAttribute = getOption(options, "userPasswordAttribute", _userPasswordAttribute); + _roleObjectClass = getOption(options, "roleObjectClass", _roleObjectClass); + _roleMemberAttribute = getOption(options, "roleMemberAttribute", _roleMemberAttribute); + _roleNameAttribute = getOption(options, "roleNameAttribute", _roleNameAttribute); + _debug = Boolean.parseBoolean(String.valueOf(getOption(options, "debug", Boolean.toString(_debug)))); + + try + { + _rootContext = new InitialDirContext(getEnvironment()); + } + catch (NamingException ex) + { + throw new IllegalStateException("Unable to establish root context", ex); + } + } + + public boolean commit() throws LoginException + { + try + { + _rootContext.close(); + } + catch (NamingException e) + { + throw new LoginException( "error closing root context: " + e.getMessage() ); + } + + return super.commit(); + } + + public boolean abort() throws LoginException + { + try + { + _rootContext.close(); + } + catch (NamingException e) + { + throw new LoginException( "error closing root context: " + e.getMessage() ); + } + + return super.abort(); + } + + private String getOption(Map<String,?> options, String key, String defaultValue) + { + Object value = options.get(key); + + if (value == null) + { + return defaultValue; + } + + return (String) value; + } + + /** + * get the context for connection + * + * @return the environment details for the context + */ + public Hashtable<Object, Object> getEnvironment() + { + Properties env = new Properties(); + + env.put(Context.INITIAL_CONTEXT_FACTORY, _contextFactory); + + if (_hostname != null) + { + env.put(Context.PROVIDER_URL, (_useLdaps?"ldaps://":"ldap://") + _hostname + (_port==0?"":":"+_port) +"/"); + } + + if (_authenticationMethod != null) + { + env.put(Context.SECURITY_AUTHENTICATION, _authenticationMethod); + } + + if (_bindDn != null) + { + env.put(Context.SECURITY_PRINCIPAL, _bindDn); + } + + if (_bindPassword != null) + { + env.put(Context.SECURITY_CREDENTIALS, _bindPassword); + } + + return env; + } + + public static String convertCredentialJettyToLdap(String encryptedPassword) + { + if ("MD5:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) + { + return "{MD5}" + encryptedPassword.substring("MD5:".length(), encryptedPassword.length()); + } + + if ("CRYPT:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) + { + return "{CRYPT}" + encryptedPassword.substring("CRYPT:".length(), encryptedPassword.length()); + } + + return encryptedPassword; + } + + public static String convertCredentialLdapToJetty(String encryptedPassword) + { + if (encryptedPassword == null) + { + return encryptedPassword; + } + + if ("{MD5}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) + { + return "MD5:" + encryptedPassword.substring("{MD5}".length(), encryptedPassword.length()); + } + + if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH))) + { + return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length(), encryptedPassword.length()); + } + + return encryptedPassword; + } +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java new file mode 100644 index 0000000000..ab5ee46aa7 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java @@ -0,0 +1,134 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; + +import org.eclipse.jetty.util.security.Credential; +import org.eclipse.jetty.security.PropertyUserStore; +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * PropertyFileLoginModule + * + * + */ +public class PropertyFileLoginModule extends AbstractLoginModule +{ + public static final String DEFAULT_FILENAME = "realm.properties"; + + private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class); + + private static ConcurrentHashMap<String, PropertyUserStore> _propertyUserStores = new ConcurrentHashMap<String, PropertyUserStore>(); + + private int _refreshInterval = 0; + private String _filename = DEFAULT_FILENAME; + + /** + * Read contents of the configured property file. + * + * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, + * java.util.Map) + * @param subject + * @param callbackHandler + * @param sharedState + * @param options + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) + { + super.initialize(subject,callbackHandler,sharedState,options); + setupPropertyUserStore(options); + } + + private void setupPropertyUserStore(Map<String, ?> options) + { + parseConfig(options); + + if (_propertyUserStores.get(_filename) == null) + { + PropertyUserStore propertyUserStore = new PropertyUserStore(); + propertyUserStore.setConfig(_filename); + propertyUserStore.setRefreshInterval(_refreshInterval); + + PropertyUserStore prev = _propertyUserStores.putIfAbsent(_filename, propertyUserStore); + if (prev == null) + { + LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval); + + try + { + propertyUserStore.start(); + } + catch (Exception e) + { + LOG.warn("Exception while starting propertyUserStore: ",e); + } + } + } + } + + private void parseConfig(Map<String, ?> options) + { + _filename = (String)options.get("file"); + _filename = (_filename == null? DEFAULT_FILENAME : _filename); + String refreshIntervalString = (String)options.get("refreshInterval"); + _refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString); + } + + /** + * Don't implement this as we want to pre-fetch all of the users. + * + * @param userName + * @throws Exception + */ + public UserInfo getUserInfo(String userName) throws Exception + { + PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename); + if (propertyUserStore == null) + throw new IllegalStateException("PropertyUserStore should never be null here!"); + + UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName); + if(userIdentity==null) + return null; + + Set<Principal> principals = userIdentity.getSubject().getPrincipals(); + + List<String> roles = new ArrayList<String>(); + + for ( Principal principal : principals ) + { + roles.add( principal.getName() ); + } + + Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next(); + LOG.debug("Found: " + userName + " in PropertyUserStore"); + return new UserInfo(userName, credential, roles); + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java new file mode 100644 index 0000000000..225e3fa25d --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/UserInfo.java @@ -0,0 +1,73 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.jaas.spi; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.util.security.Credential; + +/** + * UserInfo + * + * This is the information read from the external source + * about a user. + * + * Can be cached by a UserInfoCache implementation + */ +public class UserInfo +{ + + private String _userName; + private Credential _credential; + private List<String> _roleNames; + + + public UserInfo (String userName, Credential credential, List<String> roleNames) + { + _userName = userName; + _credential = credential; + _roleNames = new ArrayList<String>(); + if (roleNames != null) + { + _roleNames.addAll(roleNames); + } + } + + public String getUserName() + { + return this._userName; + } + + public List<String> getRoleNames () + { + return new ArrayList<String>(_roleNames); + } + + public boolean checkCredential (Object suppliedCredential) + { + return _credential.check(suppliedCredential); + } + + protected Credential getCredential () + { + return _credential; + } + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java index 20c0ef95d9..64ce0a3979 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java @@ -38,11 +38,11 @@ import org.eclipse.jetty.util.log.Logger; public class NamingEntryUtil { private static Logger __log = NamingUtil.__log; - + /** * Link a name in a webapp's java:/comp/evn namespace to a pre-existing * resource. The pre-existing resource can be either in the webapp's - * naming environment, or in the container's naming environment. Webapp's + * naming environment, or in the container's naming environment. Webapp's * environment takes precedence over the server's namespace. * * @param scope the scope of the lookup @@ -52,28 +52,28 @@ public class NamingEntryUtil */ public static boolean bindToENC (Object scope, String asName, String mappedName) throws NamingException - { + { if (asName==null||asName.trim().equals("")) throw new NamingException ("No name for NamingEntry"); if (mappedName==null || "".equals(mappedName)) mappedName=asName; - + NamingEntry entry = lookupNamingEntry (scope, mappedName); if (entry == null) return false; - + entry.bindToENC(asName); return true; } - - - + + + /** * Find a NamingEntry in the given scope. - * + * * @param scope * @param jndiName * @return the naming entry for the given scope @@ -84,12 +84,12 @@ public class NamingEntryUtil { NamingEntry entry = null; try - { + { Name scopeName = getNameForScope(scope); - InitialContext ic = new InitialContext(); + InitialContext ic = new InitialContext(); NameParser parser = ic.getNameParser(""); - Name namingEntryName = makeNamingEntryName(parser, jndiName); - scopeName.addAll(namingEntryName); + Name namingEntryName = makeNamingEntryName(parser, jndiName); + scopeName.addAll(namingEntryName); entry = (NamingEntry)ic.lookup(scopeName); } catch (NameNotFoundException ee) @@ -98,7 +98,7 @@ public class NamingEntryUtil return entry; } - + public static Object lookup(Object scope, String jndiName) throws NamingException { Name scopeName = getNameForScope(scope); @@ -108,18 +108,18 @@ public class NamingEntryUtil return ic.lookup(scopeName); } - /** + /** * Get all NameEntries of a certain type in the given naming * environment scope (server-wide names or context-specific names) - * - * @param scope + * + * @param scope * @param clazz the type of the entry * @return all NameEntries of a certain type in the given naming environment scope (server-wide names or context-specific names) * @throws NamingException */ public static List<Object> lookupNamingEntries (Object scope, Class<?> clazz) throws NamingException - { + { try { Context scopeContext = getContextForScope(scope); @@ -130,35 +130,35 @@ public class NamingEntryUtil } catch (NameNotFoundException e) { - return Collections.emptyList(); + return Collections.emptyList(); } } - - + + public static Name makeNamingEntryName (NameParser parser, NamingEntry namingEntry) throws NamingException { return makeNamingEntryName(parser, (namingEntry==null?null:namingEntry.getJndiName())); } - + public static Name makeNamingEntryName (NameParser parser, String jndiName) throws NamingException { if (jndiName==null) return null; - + if (parser==null) { InitialContext ic = new InitialContext(); parser = ic.getNameParser(""); } - + Name name = parser.parse(""); name.add(NamingEntry.__contextName); name.addAll(parser.parse(jndiName)); return name; } - + public static Name getNameForScope (Object scope) { @@ -170,7 +170,7 @@ public class NamingEntryUtil if (scope != null) { name.add(canonicalizeScope(scope)); - } + } return name; } catch (NamingException e) @@ -189,10 +189,10 @@ public class NamingEntryUtil if (scope != null) { name.add(canonicalizeScope(scope)); - } + } return (Context)ic.lookup(name); } - + public static Context getContextForNamingEntries (Object scope) throws NamingException { @@ -202,7 +202,7 @@ public class NamingEntryUtil /** * Build up a list of NamingEntry objects that are of a specific type. - * + * * @param list * @param context * @param clazz diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java index 96e9ae0e1d..1c48ff298f 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java @@ -24,7 +24,6 @@ import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -78,13 +77,13 @@ public class DataSourceLoginService extends MappedLoginService public DataSourceLoginService() { } - + /* ------------------------------------------------------------ */ public DataSourceLoginService(String name) { setName(name); } - + /* ------------------------------------------------------------ */ public DataSourceLoginService(String name, IdentityService identityService) { @@ -285,38 +284,36 @@ public class DataSourceLoginService extends MappedLoginService /* ------------------------------------------------------------ */ /** Load user's info from database. - * + * * @param userName */ @Override protected UserIdentity loadUser (String userName) { + Connection connection = null; try - { + { initDb(); - try (Connection connection = getConnection(); - PreparedStatement statement1 = connection.prepareStatement(_userSql)) + connection = getConnection(); + + PreparedStatement statement = connection.prepareStatement(_userSql); + statement.setObject(1, userName); + ResultSet rs = statement.executeQuery(); + + if (rs.next()) { - statement1.setObject(1, userName); - try (ResultSet rs1 = statement1.executeQuery()) - { - if (rs1.next()) - { - int key = rs1.getInt(_userTableKey); - String credentials = rs1.getString(_userTablePasswordField); - List<String> roles = new ArrayList<String>(); - try (PreparedStatement statement2 = connection.prepareStatement(_roleSql)) - { - statement2.setInt(1, key); - try (ResultSet rs2 = statement2.executeQuery()) - { - while (rs2.next()) - roles.add(rs2.getString(_roleTableRoleField)); - } - } - return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()])); - } - } + int key = rs.getInt(_userTableKey); + String credentials = rs.getString(_userTablePasswordField); + statement.close(); + + statement = connection.prepareStatement(_roleSql); + statement.setInt(1, key); + rs = statement.executeQuery(); + List<String> roles = new ArrayList<String>(); + while (rs.next()) + roles.add(rs.getString(_roleTableRoleField)); + statement.close(); + return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()])); } } catch (NamingException e) @@ -327,28 +324,46 @@ public class DataSourceLoginService extends MappedLoginService { LOG.warn("Problem loading user info for "+userName, e); } + finally + { + if (connection != null) + { + try + { + connection.close(); + } + catch (SQLException x) + { + LOG.warn("Problem closing connection", x); + } + finally + { + connection = null; + } + } + } return null; } - + /* ------------------------------------------------------------ */ /** * Lookup the datasource for the jndiName and formulate the * necessary sql query strings based on the configured table * and column names. - * + * * @throws NamingException */ public void initDb() throws NamingException, SQLException { if (_datasource != null) return; - + @SuppressWarnings("unused") InitialContext ic = new InitialContext(); assert ic!=null; - + //TODO webapp scope? - + //try finding the datasource in the Server scope if (_server != null) { @@ -361,7 +376,7 @@ public class DataSourceLoginService extends MappedLoginService //next try the jvm scope } } - + //try finding the datasource in the jvm scope if (_datasource==null) @@ -370,111 +385,110 @@ public class DataSourceLoginService extends MappedLoginService } // set up the select statements based on the table and column names configured - _userSql = "select " + _userTableKey + "," + _userTablePasswordField - + " from " + _userTableName + _userSql = "select " + _userTableKey + "," + _userTablePasswordField + + " from " + _userTableName + " where "+ _userTableUserField + " = ?"; - + _roleSql = "select r." + _roleTableRoleField - + " from " + _roleTableName + " r, " + _userRoleTableName + + " from " + _roleTableName + " r, " + _userRoleTableName + " u where u."+ _userRoleTableUserKey + " = ?" + " and r." + _roleTableKey + " = u." + _userRoleTableRoleKey; - + prepareTables(); } - - - + + + private void prepareTables() throws NamingException, SQLException { + Connection connection = null; + boolean autocommit = true; + if (_createTables) { - boolean autocommit = true; - Connection connection = getConnection(); - try (Statement stmt = connection.createStatement()) + try { + connection = getConnection(); autocommit = connection.getAutoCommit(); connection.setAutoCommit(false); DatabaseMetaData metaData = connection.getMetaData(); - + //check if tables exist String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(Locale.ENGLISH): _userTableName)); - try (ResultSet result = metaData.getTables(null, null, tableName, null)) - { - if (!result.next()) - { - //user table default - /* - * create table _userTableName (_userTableKey integer, - * _userTableUserField varchar(100) not null unique, - * _userTablePasswordField varchar(20) not null, primary key(_userTableKey)); - */ - stmt.executeUpdate("create table "+_userTableName+ "("+_userTableKey+" integer,"+ - _userTableUserField+" varchar(100) not null unique,"+ - _userTablePasswordField+" varchar(20) not null, primary key("+_userTableKey+"))"); - if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userTableName); - } + ResultSet result = metaData.getTables(null, null, tableName, null); + if (!result.next()) + { + //user table default + /* + * create table _userTableName (_userTableKey integer, + * _userTableUserField varchar(100) not null unique, + * _userTablePasswordField varchar(20) not null, primary key(_userTableKey)); + */ + connection.createStatement().executeUpdate("create table "+_userTableName+ "("+_userTableKey+" integer,"+ + _userTableUserField+" varchar(100) not null unique,"+ + _userTablePasswordField+" varchar(20) not null, primary key("+_userTableKey+"))"); + if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userTableName); } + + result.close(); tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(Locale.ENGLISH): _roleTableName)); - try (ResultSet result = metaData.getTables(null, null, tableName, null)) + result = metaData.getTables(null, null, tableName, null); + if (!result.next()) { - if (!result.next()) - { - //role table default - /* - * create table _roleTableName (_roleTableKey integer, - * _roleTableRoleField varchar(100) not null unique, primary key(_roleTableKey)); - */ - String str = "create table "+_roleTableName+" ("+_roleTableKey+" integer, "+ - _roleTableRoleField+" varchar(100) not null unique, primary key("+_roleTableKey+"))"; - stmt.executeUpdate(str); - if (LOG.isDebugEnabled()) LOG.debug("Created table "+_roleTableName); - } + //role table default + /* + * create table _roleTableName (_roleTableKey integer, + * _roleTableRoleField varchar(100) not null unique, primary key(_roleTableKey)); + */ + String str = "create table "+_roleTableName+" ("+_roleTableKey+" integer, "+ + _roleTableRoleField+" varchar(100) not null unique, primary key("+_roleTableKey+"))"; + connection.createStatement().executeUpdate(str); + if (LOG.isDebugEnabled()) LOG.debug("Created table "+_roleTableName); } + + result.close(); tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(Locale.ENGLISH): _userRoleTableName)); - try (ResultSet result = metaData.getTables(null, null, tableName, null)) + result = metaData.getTables(null, null, tableName, null); + if (!result.next()) { - if (!result.next()) - { - //user-role table - /* - * create table _userRoleTableName (_userRoleTableUserKey integer, - * _userRoleTableRoleKey integer, - * primary key (_userRoleTableUserKey, _userRoleTableRoleKey)); - * - * create index idx_user_role on _userRoleTableName (_userRoleTableUserKey); - */ - stmt.executeUpdate("create table "+_userRoleTableName+" ("+_userRoleTableUserKey+" integer, "+ - _userRoleTableRoleKey+" integer, "+ - "primary key ("+_userRoleTableUserKey+", "+_userRoleTableRoleKey+"))"); - stmt.executeUpdate("create index indx_user_role on "+_userRoleTableName+"("+_userRoleTableUserKey+")"); - if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userRoleTableName +" and index"); - } + //user-role table + /* + * create table _userRoleTableName (_userRoleTableUserKey integer, + * _userRoleTableRoleKey integer, + * primary key (_userRoleTableUserKey, _userRoleTableRoleKey)); + * + * create index idx_user_role on _userRoleTableName (_userRoleTableUserKey); + */ + connection.createStatement().executeUpdate("create table "+_userRoleTableName+" ("+_userRoleTableUserKey+" integer, "+ + _userRoleTableRoleKey+" integer, "+ + "primary key ("+_userRoleTableUserKey+", "+_userRoleTableRoleKey+"))"); + connection.createStatement().executeUpdate("create index indx_user_role on "+_userRoleTableName+"("+_userRoleTableUserKey+")"); + if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userRoleTableName +" and index"); } + + result.close(); connection.commit(); } finally { - try - { - connection.setAutoCommit(autocommit); - } - catch (SQLException e) - { - if (LOG.isDebugEnabled()) LOG.debug("Prepare tables", e); - } - finally + if (connection != null) { try { + connection.setAutoCommit(autocommit); connection.close(); } catch (SQLException e) { if (LOG.isDebugEnabled()) LOG.debug("Prepare tables", e); } + finally + { + connection = null; + } } } } @@ -483,9 +497,9 @@ public class DataSourceLoginService extends MappedLoginService LOG.debug("createTables false"); } } - - - private Connection getConnection () + + + private Connection getConnection () throws NamingException, SQLException { initDb(); diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/package-info.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/package-info.java deleted file mode 100644 index 33606e8b7b..0000000000 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2013 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. -// ======================================================================== -// - -/** - * Jetty Plus : Limited JEE Security Support - */ -package org.eclipse.jetty.plus.security; - diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/servlet/ServletHandler.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/servlet/ServletHandler.java new file mode 100644 index 0000000000..ab2e127f63 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/servlet/ServletHandler.java @@ -0,0 +1,76 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.plus.servlet; + +import org.eclipse.jetty.plus.annotation.InjectionCollection; +import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; + +/** + * ServletHandler + * + * + */ +public class ServletHandler extends org.eclipse.jetty.servlet.ServletHandler +{ + + private InjectionCollection _injections = null; + private LifeCycleCallbackCollection _callbacks = null; + + + + /** + * @return the callbacks + */ + public LifeCycleCallbackCollection getCallbacks() + { + return _callbacks; + } + + + + /** + * @param callbacks the callbacks to set + */ + public void setCallbacks(LifeCycleCallbackCollection callbacks) + { + this._callbacks = callbacks; + } + + + + /** + * @return the injections + */ + public InjectionCollection getInjections() + { + return _injections; + } + + + + /** + * @param injections the injections to set + */ + public void setInjections(InjectionCollection injections) + { + this._injections = injections; + } + + +} diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java index 26227f1555..0fb9c43ed3 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java @@ -31,7 +31,6 @@ import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NamingException; -import org.eclipse.jetty.jndi.ContextFactory; import org.eclipse.jetty.jndi.NamingContext; import org.eclipse.jetty.jndi.NamingUtil; import org.eclipse.jetty.jndi.local.localContextRoot; @@ -62,26 +61,26 @@ public class EnvConfiguration extends AbstractConfiguration this.jettyEnvXmlUrl = url; } - /** + /** * @see Configuration#configure(WebAppContext) * @throws Exception */ @Override public void preConfigure (WebAppContext context) throws Exception - { + { //create a java:comp/env createEnvContext(context); } - /** + /** * @throws Exception */ @Override public void configure (WebAppContext context) throws Exception - { + { if (LOG.isDebugEnabled()) LOG.debug("Created java:comp/env for webapp "+context.getContextPath()); - + //check to see if an explicit file has been set, if not, //look in WEB-INF/jetty-env.xml if (jettyEnvXmlUrl == null) @@ -98,7 +97,7 @@ public class EnvConfiguration extends AbstractConfiguration } } } - + if (jettyEnvXmlUrl != null) { synchronized (localContextRoot.getRoot()) @@ -136,8 +135,8 @@ public class EnvConfiguration extends AbstractConfiguration bindEnvEntries(context); } - - /** + + /** * Remove jndi setup from start * @see Configuration#deconfigure(WebAppContext) * @throws Exception @@ -148,7 +147,6 @@ public class EnvConfiguration extends AbstractConfiguration //get rid of any bindings for comp/env for webapp ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(context.getClassLoader()); - ContextFactory.associateClassLoader(context.getClassLoader()); try { Context ic = new InitialContext(); @@ -172,13 +170,12 @@ public class EnvConfiguration extends AbstractConfiguration } finally { - ContextFactory.disassociateClassLoader(); Thread.currentThread().setContextClassLoader(oldLoader); } } - - /** + + /** * Remove all jndi setup * @see Configuration#deconfigure(WebAppContext) * @throws Exception @@ -187,7 +184,7 @@ public class EnvConfiguration extends AbstractConfiguration public void destroy (WebAppContext context) throws Exception { try - { + { //unbind any NamingEntries that were configured in this webapp's name space NamingContext scopeContext = (NamingContext)NamingEntryUtil.getContextForScope(context); scopeContext.getParent().destroySubcontext(scopeContext.getName()); @@ -198,11 +195,11 @@ public class EnvConfiguration extends AbstractConfiguration LOG.debug("No naming entries configured in environment for webapp "+context); } } - + /** * Bind all EnvEntries that have been declared, so that the processing of the * web.xml file can potentially override them. - * + * * We first bind EnvEntries declared in Server scope, then WebAppContext scope. * @throws NamingException */ @@ -220,11 +217,11 @@ public class EnvConfiguration extends AbstractConfiguration EnvEntry ee = (EnvEntry)itor.next(); ee.bindToENC(ee.getJndiName()); Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee); - NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later + NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later } - + LOG.debug("Binding env entries from the server scope"); - + scope = context.getServer(); list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class); itor = list.iterator(); @@ -233,9 +230,9 @@ public class EnvConfiguration extends AbstractConfiguration EnvEntry ee = (EnvEntry)itor.next(); ee.bindToENC(ee.getJndiName()); Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee); - NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later + NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later } - + LOG.debug("Binding env entries from the context scope"); scope = context; list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class); @@ -247,27 +244,25 @@ public class EnvConfiguration extends AbstractConfiguration Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee); NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later } - } - + } + protected void createEnvContext (WebAppContext wac) throws NamingException { ClassLoader old_loader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(wac.getClassLoader()); - ContextFactory.associateClassLoader(wac.getClassLoader()); try { Context context = new InitialContext(); Context compCtx = (Context)context.lookup ("java:comp"); compCtx.createSubcontext("env"); } - finally + finally { - ContextFactory.disassociateClassLoader(); - Thread.currentThread().setContextClassLoader(old_loader); - } + Thread.currentThread().setContextClassLoader(old_loader); + } } - + private static class Bound { final NamingContext _context; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java index 3962994d5d..178e17391a 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java @@ -43,18 +43,18 @@ public class PlusConfiguration extends AbstractConfiguration private static final Logger LOG = Log.getLogger(PlusConfiguration.class); private Integer _key; - + @Override public void preConfigure (WebAppContext context) throws Exception - { - context.addDecorator(new PlusDecorator(context)); + { + context.addDecorator(new PlusDecorator(context)); } - + @Override public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception { - context.addDecorator(new PlusDecorator(context)); + context.addDecorator(new PlusDecorator(context)); } @Override @@ -62,7 +62,7 @@ public class PlusConfiguration extends AbstractConfiguration throws Exception { bindUserTransaction(context); - + context.getMetaData().addDescriptorProcessor(new PlusDescriptorProcessor()); } @@ -82,7 +82,7 @@ public class PlusConfiguration extends AbstractConfiguration context.setAttribute(InjectionCollection.INJECTION_COLLECTION,null); context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION,null); } - + public void bindUserTransaction (WebAppContext context) throws Exception { @@ -92,12 +92,12 @@ public class PlusConfiguration extends AbstractConfiguration } catch (NameNotFoundException e) { - LOG.debug("No Transaction manager found - if your webapp requires one, please configure one."); + LOG.info("No Transaction manager found - if your webapp requires one, please configure one."); } } - - - + + + protected void lockCompEnv (WebAppContext wac) throws Exception { @@ -116,7 +116,7 @@ public class PlusConfiguration extends AbstractConfiguration Thread.currentThread().setContextClassLoader(old_loader); } } - + protected void unlockCompEnv (WebAppContext wac) throws Exception { @@ -129,7 +129,7 @@ public class PlusConfiguration extends AbstractConfiguration { Context context = new InitialContext(); Context compCtx = (Context)context.lookup("java:comp"); - compCtx.addToEnvironment("org.eclipse.jndi.unlock", _key); + compCtx.addToEnvironment("org.eclipse.jndi.unlock", _key); } finally { diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java index 68f50bcb3b..4b4f19f5e5 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java @@ -57,7 +57,7 @@ public class PlusDecorator implements Decorator public void decorateFilterHolder(FilterHolder filter) throws ServletException { } - + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateFilterInstance(javax.servlet.Filter) @@ -86,7 +86,7 @@ public class PlusDecorator implements Decorator { decorate(holder); } - + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#decorateServletInstance(javax.servlet.Servlet) @@ -116,7 +116,7 @@ public class PlusDecorator implements Decorator destroy(s); } - /** + /** * @see org.eclipse.jetty.servlet.ServletContextHandler.Decorator#destroyListenerInstance(java.util.EventListener) */ public void destroyListenerInstance(EventListener l) @@ -125,14 +125,14 @@ public class PlusDecorator implements Decorator } - protected void decorate (Object o) + protected void decorate (Object o) throws ServletException - { + { RunAsCollection runAses = (RunAsCollection)_context.getAttribute(RunAsCollection.RUNAS_COLLECTION); if (runAses != null) runAses.setRunAs(o); - + InjectionCollection injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION); if (injections != null) injections.inject(o); @@ -149,11 +149,11 @@ public class PlusDecorator implements Decorator throw new ServletException(e); } } - } - + } + protected void destroy (Object o) { - LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); + LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); if (callbacks != null) { try diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java index bddd017acd..beb9f9e7be 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java @@ -73,11 +73,11 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } - /** + /** * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(WebAppContext, org.eclipse.jetty.webapp.Descriptor) */ public void start(WebAppContext context, Descriptor descriptor) - { + { InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION); if (injections == null) @@ -97,24 +97,24 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor if (runAsCollection == null) { runAsCollection = new RunAsCollection(); - context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection); + context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection); } } - - /** + + /** * {@inheritDoc} */ public void end(WebAppContext context,Descriptor descriptor) { } - - - + + + /** - * JavaEE 5.4.1.3 - * + * JavaEE 5.4.1.3 + * * @param node * @throws Exception */ @@ -124,7 +124,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String name=node.getString("env-entry-name",false,true); String type = node.getString("env-entry-type",false,true); String valueStr = node.getString("env-entry-value",false,true); - + //if there's no value there's no point in making a jndi entry //nor processing injection entries if (valueStr==null || valueStr.equals("")) @@ -132,7 +132,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor LOG.warn("No value for env-entry-name "+name); return; } - + Origin o = context.getMetaData().getOrigin("env-entry."+name); switch (o) { @@ -147,7 +147,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //of the first one? addInjections (context, descriptor, node, name, TypeUtil.fromName(type)); Object value = TypeUtil.valueOf(type,valueStr); - bindEnvEntry(name, value); + bindEnvEntry(name, value); break; } case WebXml: @@ -164,7 +164,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor context.getMetaData().setOrigin("env-entry."+name, descriptor); addInjections (context, descriptor, node, name, TypeUtil.fromName(type)); Object value = TypeUtil.valueOf(type,valueStr); - bindEnvEntry(name, value); + bindEnvEntry(name, value); } else { @@ -184,8 +184,8 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } } - - + + /** * Common Annotations Spec section 2.3: * resource-ref is for: @@ -198,11 +198,11 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor * - javax.resource.cci.ConnectionFactory * - org.omg.CORBA_2_3.ORB * - any other connection factory defined by a resource adapter - * + * * TODO * If web.xml contains a resource-ref with injection targets, all resource-ref entries * of the same name are ignored in web fragments. If web.xml does not contain any - * injection-targets, then they are merged from all the fragments. + * injection-targets, then they are merged from all the fragments. * If web.xml does not contain a resource-ref element of same name, but 2 fragments * declare the same name it is an error. * resource-ref entries are ONLY for connection factories @@ -211,20 +211,20 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor * a real resource in the environment. At the moment, we insist that the * jetty.xml file name of the resource has to be exactly the same as the * name in web.xml deployment descriptor, but it shouldn't have to be - * + * * Maintenance update 3.0a to spec: - * Update Section 8.2.3.h.ii with the following - If a resource reference - * element is specified in two fragments, while absent from the main web.xml, - * and all the attributes and child elements of the resource reference element - * are identical, the resource reference will be merged into the main web.xml. - * It is considered an error if a resource reference element has the same name - * specified in two fragments, while absent from the main web.xml and the attributes - * and child elements are not identical in the two fragments. For example, if two - * web fragments declare a <resource-ref> with the same <resource-ref-name> element - * but the type in one is specified as javax.sql.DataSource while the type in the - * other is that of a java mail resource, then an error must be reported and the + * Update Section 8.2.3.h.ii with the following - If a resource reference + * element is specified in two fragments, while absent from the main web.xml, + * and all the attributes and child elements of the resource reference element + * are identical, the resource reference will be merged into the main web.xml. + * It is considered an error if a resource reference element has the same name + * specified in two fragments, while absent from the main web.xml and the attributes + * and child elements are not identical in the two fragments. For example, if two + * web fragments declare a <resource-ref> with the same <resource-ref-name> element + * but the type in one is specified as javax.sql.DataSource while the type in the + * other is that of a java mail resource, then an error must be reported and the * application MUST fail to deploy. - * + * * @param node * @throws Exception */ @@ -235,7 +235,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String type = node.getString("res-type", false, true); String auth = node.getString("res-auth", false, true); String shared = node.getString("res-sharing-scope", false, true); - + Origin o = context.getMetaData().getOrigin("resource-ref."+jndiName); switch (o) { @@ -243,45 +243,45 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //No descriptor or annotation previously declared a resource-ref of this name. context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor); - + //check for <injection> elements Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); - addInjections(context, descriptor, node, jndiName, typeClass); + addInjections(context, descriptor, node, jndiName, typeClass); bindResourceRef(context,jndiName, typeClass); break; } case WebXml: case WebDefaults: - case WebOverride: + case WebOverride: { - //A web xml previously declared the resource-ref. + //A web xml previously declared the resource-ref. if (!(descriptor instanceof FragmentDescriptor)) { //We're processing web-defaults, web.xml or web-override. Any of them can //set or change the resource-ref. context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor); - + //check for <injection> elements Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); - + addInjections(context, descriptor, node, jndiName, typeClass); - + //bind the entry into jndi bindResourceRef(context,jndiName, typeClass); } else { - //A web xml declared the resource-ref and we're processing a - //web-fragment. Check to see if any injections were declared for it by web.xml. + //A web xml declared the resource-ref and we're processing a + //web-fragment. Check to see if any injections were declared for it by web.xml. //If any injection was declared in web.xml then don't merge any injections. //If it was declared in a web-fragment, then we can keep merging fragments. Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref."+jndiName+".injection"); if (d==null || d instanceof FragmentDescriptor) - { + { Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); @@ -291,7 +291,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor break; } case WebFragment: - { + { Descriptor otherFragment = context.getMetaData().getOriginDescriptor("resource-ref."+jndiName); XmlParser.Node otherFragmentRoot = otherFragment.getRoot(); Iterator<Object> iter = otherFragmentRoot.iterator(); @@ -304,7 +304,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor if ("resource-ref".equals(n.getTag()) && jndiName.equals(n.getString("res-ref-name",false,true))) otherNode = n; } - + //If declared in another web-fragment if (otherNode != null) { @@ -312,7 +312,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String otherType = otherNode.getString("res-type", false, true); String otherAuth = otherNode.getString("res-auth", false, true); String otherShared = otherNode.getString("res-sharing-scope", false, true); - + //otherType, otherAuth and otherShared must be the same as type, auth, shared type = (type == null?"":type); otherType = (otherType == null?"":otherType); @@ -320,7 +320,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor otherAuth = (otherAuth == null?"":otherAuth); shared = (shared == null?"":shared); otherShared = (otherShared == null?"":otherShared); - + //ServletSpec p.75. No declaration of resource-ref in web xml, but different in multiple web-fragments. Error. if (!type.equals(otherType) || !auth.equals(otherAuth) || !shared.equals(otherShared)) throw new IllegalStateException("Conflicting resource-ref "+jndiName+" in "+descriptor.getResource()); @@ -329,20 +329,20 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } else throw new IllegalStateException("resource-ref."+jndiName+" not found in declaring descriptor "+otherFragment); - + } } - + } - - + + /** * Common Annotations Spec section 2.3: * resource-env-ref is for: * - javax.transaction.UserTransaction * - javax.resource.cci.InteractionSpec * - anything else that is not a connection factory - * + * * @param node * @throws Exception */ @@ -351,7 +351,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { String jndiName = node.getString("resource-env-ref-name",false,true); String type = node.getString("resource-env-ref-type", false, true); - + Origin o = context.getMetaData().getOrigin("resource-env-ref."+jndiName); switch (o) { @@ -369,7 +369,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } case WebXml: case WebDefaults: - case WebOverride: + case WebOverride: { //A resource-env-ref of this name has been declared first in a web xml. //Only allow other web-default, web.xml, web-override to change it. @@ -382,7 +382,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor if (typeClass==null) typeClass = context.loadClass(type); addInjections (context, descriptor, node, jndiName, typeClass); - bindResourceEnvRef(context,jndiName, typeClass); + bindResourceEnvRef(context,jndiName, typeClass); } else { @@ -424,8 +424,8 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //ServletSpec p.75. No declaration of resource-ref in web xml, but different in multiple web-fragments. Error. if (!type.equals(otherType)) - throw new IllegalStateException("Conflicting resource-env-ref "+jndiName+" in "+descriptor.getResource()); - + throw new IllegalStateException("Conflicting resource-env-ref "+jndiName+" in "+descriptor.getResource()); + //same in multiple web-fragments, merge the injections addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); } @@ -450,25 +450,25 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String jndiName = node.getString("message-destination-ref-name",false,true); String type = node.getString("message-destination-type",false,true); String usage = node.getString("message-destination-usage",false,true); - + Origin o = context.getMetaData().getOrigin("message-destination-ref."+jndiName); switch (o) { case NotSet: - { + { //A message-destination-ref of this name has not been previously declared Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); - addInjections(context, descriptor, node, jndiName, typeClass); + addInjections(context, descriptor, node, jndiName, typeClass); bindMessageDestinationRef(context,jndiName, typeClass); context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor); break; } case WebXml: case WebDefaults: - case WebOverride: - { + case WebOverride: + { //A message-destination-ref of this name has been declared first in a web xml. //Only allow other web-default, web.xml, web-override to change it. if (!(descriptor instanceof FragmentDescriptor)) @@ -476,7 +476,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); - addInjections(context, descriptor, node, jndiName, typeClass); + addInjections(context, descriptor, node, jndiName, typeClass); bindMessageDestinationRef(context,jndiName, typeClass); context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor); } @@ -486,11 +486,11 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //It can only contribute injections, and only if the web xml didn't declare any. Descriptor d = context.getMetaData().getOriginDescriptor("message-destination-ref."+jndiName+".injection"); if (d == null || d instanceof FragmentDescriptor) - { + { Class<?> typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = context.loadClass(type); - addInjections(context, descriptor, node, jndiName, typeClass); + addInjections(context, descriptor, node, jndiName, typeClass); } } break; @@ -518,7 +518,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor usage = (usage==null?"":usage); if (!type.equals(otherType) || !usage.equalsIgnoreCase(otherUsage)) throw new IllegalStateException("Conflicting message-destination-ref "+jndiName+" in "+descriptor.getResource()); - + //same in multiple web-fragments, merge the injections addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); } @@ -528,8 +528,8 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } - - + + /** * If web.xml has at least 1 post-construct, then all post-constructs in fragments @@ -542,7 +542,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { String className = node.getString("lifecycle-callback-class", false, true); String methodName = node.getString("lifecycle-callback-method", false, true); - + if (className==null || className.equals("")) { LOG.warn("No lifecycle-callback-class specified"); @@ -553,7 +553,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor LOG.warn("No lifecycle-callback-method specified for class "+className); return; } - + //ServletSpec 3.0 p80 If web.xml declares a post-construct then all post-constructs //in fragments must be ignored. Otherwise, they are additive. Origin o = context.getMetaData().getOrigin("post-construct"); @@ -563,7 +563,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //No post-constructs have been declared previously. context.getMetaData().setOrigin("post-construct", descriptor); - + try { Class<?> clazz = context.loadClass(className); @@ -579,7 +579,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } case WebXml: case WebDefaults: - case WebOverride: + case WebOverride: { //A web xml first declared a post-construct. Only allow other web xml files (web-defaults, web-overrides etc) //to add to it @@ -616,12 +616,12 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor break; } } - + } - + /** - * + * * pre-destroy is the name of a class and method to call just as * the instance is being destroyed * @param node @@ -639,8 +639,8 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { LOG.warn("No lifecycle-callback-method specified for pre-destroy class "+className); return; - } - + } + Origin o = context.getMetaData().getOrigin("pre-destroy"); switch(o) { @@ -664,7 +664,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } case WebXml: case WebDefaults: - case WebOverride: + case WebOverride: { //A web xml file previously declared a pre-destroy. Only allow other web xml files //(not web-fragments) to add to them. @@ -680,7 +680,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor catch (ClassNotFoundException e) { LOG.warn("Couldn't load pre-destory target class "+className); - } + } } break; } @@ -697,16 +697,16 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor catch (ClassNotFoundException e) { LOG.warn("Couldn't load pre-destory target class "+className); - } + } break; } - } + } } - - + + /** * Iterate over the <injection-target> entries for a node - * + * * @param descriptor * @param node * @param jndiName @@ -715,10 +715,10 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor public void addInjections (WebAppContext context, Descriptor descriptor, XmlParser.Node node, String jndiName, Class<?> valueClass) { Iterator<XmlParser.Node> itor = node.iterator("injection-target"); - + while(itor.hasNext()) { - XmlParser.Node injectionNode = itor.next(); + XmlParser.Node injectionNode = itor.next(); String targetClassName = injectionNode.getString("injection-target-class", false, true); String targetName = injectionNode.getString("injection-target-name", false, true); if ((targetClassName==null) || targetClassName.equals("")) @@ -747,7 +747,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor injection.setJndiName(jndiName); injection.setTarget(clazz, targetName, valueClass); injections.add(injection); - + //Record which was the first descriptor to declare an injection for this name if (context.getMetaData().getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null) context.getMetaData().setOrigin(node.getTag()+"."+jndiName+".injection", descriptor); @@ -758,17 +758,17 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } } + + - - - - /** + + /** * @param name * @param value * @throws Exception */ public void bindEnvEntry(String name, Object value) throws Exception - { + { InitialContext ic = null; boolean bound = false; //check to see if we bound a value and an EnvEntry with this name already @@ -797,12 +797,12 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } - /** + /** * Bind a resource reference. - * + * * If a resource reference with the same name is in a jetty-env.xml * file, it will already have been bound. - * + * * @param name * @throws Exception */ @@ -812,7 +812,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor bindEntry(context, name, typeClass); } - /** + /** * @param name * @throws Exception */ @@ -821,28 +821,28 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { bindEntry(context, name, typeClass); } - - + + public void bindMessageDestinationRef(WebAppContext context, String name, Class<?> typeClass) throws Exception { bindEntry(context, name, typeClass); } - - + + /** * Bind a resource with the given name from web.xml of the given type - * with a jndi resource from either the server or the webapp's naming + * with a jndi resource from either the server or the webapp's naming * environment. - * + * * As the servlet spec does not cover the mapping of names in web.xml with * names from the execution environment, jetty uses the concept of a Link, which is * a subclass of the NamingEntry class. A Link defines a mapping of a name * from web.xml with a name from the execution environment (ie either the server or the * webapp's naming environment). - * + * * @param name name of the resource from web.xml - * @param typeClass + * @param typeClass * @throws Exception */ protected void bindEntry (WebAppContext context, String name, Class<?> typeClass) @@ -850,12 +850,12 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { String nameInEnvironment = name; boolean bound = false; - + //check if the name in web.xml has been mapped to something else //check a context-specific naming environment first Object scope = context; NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name); - + if (ne!=null && (ne instanceof Link)) { //if we found a mapping, get out name it is mapped to in the environment @@ -865,10 +865,10 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //try finding that mapped name in the webapp's environment first scope = context; bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); - + if (bound) return; - + //try the server's environment scope = context.getServer(); bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); @@ -888,12 +888,12 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(context.getServer(), nameInEnvironment); if (defaultNE==null) defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment); - + if (defaultNE!=null) defaultNE.bindToENC(name); else throw new IllegalStateException("Nothing to bind for name "+nameInEnvironment); } - + } |