Issue #2445 Optionally expose request for jaas (#2463)

* Issue #2445 Optionally expose request for jaas

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2018-05-01 10:06:22 +10:00 committed by GitHub
parent 0e971e07d6
commit 44dfa868df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 206 additions and 17 deletions

View File

@ -377,11 +377,15 @@ The `AbstractLoginModule` does not support any caching, so if you want to cache
==== Other Goodies
===== ServletRequestCallback
This callback gives you access to the ServletRequest that is involved in the authentication, and thus to other features like the current Session. This callback can be configured in your custom LoginModule implementation. Note that none of the LoginModule implementations provided with Jetty currently use this callback.
===== RequestParameterCallback
As all servlet containers intercept and process a form submission with action `j_security_check`, it is usually not possible to insert any extra input fields onto a login form with which to perform authentication: you may only pass `j_username` and `j_password`.
For those rare occasions when this is not good enough, and you require more information from the user in order to authenticate them, you can use the JAAS callback handler `org.eclipse.jetty.jaas.callback.RequestParameterCallback`.
This callback handler gives you access to all parameters that were passed in the form submission.
This callback gives you access to all parameters that were passed in the form submission.
To use it, in the `login()` method of your custom login module, add the `RequestParameterCallback` to the list of callback handlers the login module uses, tell it which params you are interested in, and then get the value of the parameter back.
Here is an example:

View File

@ -31,15 +31,19 @@ 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.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.jaas.callback.ServletRequestCallback;
import org.eclipse.jetty.jaas.callback.DefaultCallbackHandler;
import org.eclipse.jetty.jaas.callback.ObjectCallback;
import org.eclipse.jetty.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.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.Loader;
@ -69,11 +73,10 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
protected String _loginModuleName;
protected JAASUserPrincipal _defaultUser = new JAASUserPrincipal(null, null, null);
protected IdentityService _identityService;
protected Configuration _configuration;
/**
*
*/
public JAASLoginService()
{
}
@ -117,7 +120,28 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/** Get the identityService.
/**
* @return the configuration
*/
public Configuration getConfiguration()
{
return _configuration;
}
/**
* @param configuration the configuration to set
*/
public void setConfiguration(Configuration configuration)
{
_configuration = configuration;
}
/**
* Get the identityService.
* @return the identityService
*/
@Override
@ -127,7 +151,8 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/** Set the identityService.
/**
* Set the identityService.
* @param identityService the identityService to set
*/
@Override
@ -189,8 +214,6 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
try
{
CallbackHandler callbackHandler = null;
if (_callbackHandlerClass == null)
{
callbackHandler = new CallbackHandler()
@ -218,6 +241,10 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
if (request!=null)
rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName())));
}
else if (callback instanceof ServletRequestCallback)
{
((ServletRequestCallback)callback).setRequest(request);
}
else
throw new UnsupportedCallbackException(callback);
}
@ -228,11 +255,20 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
{
Class<?> clazz = Loader.loadClass(_callbackHandlerClass);
callbackHandler = (CallbackHandler)clazz.getDeclaredConstructor().newInstance();
if (DefaultCallbackHandler.class.isAssignableFrom(clazz))
{
DefaultCallbackHandler dch = (DefaultCallbackHandler)callbackHandler;
if (request instanceof Request)
dch.setRequest((Request)request);
dch.setCredential(credentials);
dch.setUserName(username);
}
}
//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 loginContext = (_configuration==null?new LoginContext(_loginModuleName, subject, callbackHandler)
:new LoginContext(_loginModuleName, subject, callbackHandler, _configuration));
loginContext.login();

View File

@ -30,7 +30,10 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.security.Password;
/**
* DefaultUsernameCredentialCallbackHandler
* DefaultCallbackHandler
*
* An implementation of the JAAS CallbackHandler. Users can provide
* their own implementation instead and set the name of its class on the JAASLoginService.
*/
public class DefaultCallbackHandler extends AbstractCallbackHandler
{
@ -38,7 +41,7 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler
public void setRequest (Request request)
{
this._request = request;
_request = request;
}
@Override
@ -71,6 +74,10 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler
RequestParameterCallback callback = (RequestParameterCallback)callbacks[i];
callback.setParameterValues(Arrays.asList(_request.getParameterValues(callback.getParameterName())));
}
else if (callbacks[i] instanceof ServletRequestCallback)
{
((ServletRequestCallback)callbacks[i]).setRequest(_request);
}
else
throw new UnsupportedCallbackException(callbacks[i]);
}

View File

@ -0,0 +1,44 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.jaas.callback;
import javax.security.auth.callback.Callback;
import javax.servlet.ServletRequest;
/**
* ServletRequestCallback
*
* Provides access to the request associated with the authentication.
*/
public class ServletRequestCallback implements Callback
{
protected ServletRequest _request;
public void setRequest (ServletRequest request)
{
_request = request;
}
public ServletRequest getRequest ()
{
return _request;
}
}

View File

@ -115,6 +115,12 @@ public abstract class AbstractLoginModule implements LoginModule
}
}
public abstract UserInfo getUserInfo (String username) throws Exception;
public Subject getSubject ()
{
return this.subject;
@ -198,7 +204,6 @@ public abstract class AbstractLoginModule implements LoginModule
public Callback[] configureCallbacks ()
{
Callback[] callbacks = new Callback[3];
callbacks[0] = new NameCallback("Enter user name");
callbacks[1] = new ObjectCallback();
@ -211,9 +216,7 @@ public abstract class AbstractLoginModule implements LoginModule
{
return false;
}
public abstract UserInfo getUserInfo (String username) throws Exception;

View File

@ -23,9 +23,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.security.Principal;
import java.util.Collections;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import javax.security.auth.login.Configuration;
import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.server.Request;
import org.junit.Test;
/**
@ -35,6 +41,19 @@ import org.junit.Test;
*/
public class JAASLoginServiceTest
{
public static class TestConfiguration extends Configuration
{
AppConfigurationEntry _entry = new AppConfigurationEntry(TestLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, Collections.emptyMap());
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name)
{
return new AppConfigurationEntry[] {_entry};
}
}
interface SomeRole
{
@ -79,7 +98,24 @@ public class JAASLoginServiceTest
}
}
@Test
public void testServletRequestCallback () throws Exception
{
//Test with the DefaultCallbackHandler
JAASLoginService ls = new JAASLoginService("foo");
ls.setCallbackHandlerClass("org.eclipse.jetty.jaas.callback.DefaultCallbackHandler");
ls.setIdentityService(new DefaultIdentityService());
ls.setConfiguration(new TestConfiguration());
Request request = new Request(null, null);
ls.login("aaardvaark", "aaa", request);
//Test with the fallback CallbackHandler
ls = new JAASLoginService("foo");
ls.setIdentityService(new DefaultIdentityService());
ls.setConfiguration(new TestConfiguration());
ls.login("aaardvaark", "aaa", request);
}
@Test
public void testLoginServiceRoles () throws Exception

View File

@ -0,0 +1,59 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.jaas;
import static org.junit.Assert.assertNotNull;
import javax.security.auth.callback.Callback;
import javax.security.auth.login.LoginException;
import org.eclipse.jetty.jaas.callback.ServletRequestCallback;
import org.eclipse.jetty.jaas.spi.AbstractLoginModule;
import org.eclipse.jetty.jaas.spi.UserInfo;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.security.Password;
public class TestLoginModule extends AbstractLoginModule
{
public ServletRequestCallback _callback = new ServletRequestCallback();
@Override
public UserInfo getUserInfo(String username) throws Exception
{
return new UserInfo(username, new Password("aaa"));
}
@Override
public Callback[] configureCallbacks()
{
return ArrayUtil.addToArray(super.configureCallbacks(), _callback, Callback.class);
}
@Override
public boolean login() throws LoginException
{
boolean result = super.login();
assertNotNull(_callback.getRequest());
return result;
}
}