Initial commit of remote client authentication interface.

This commit is contained in:
Ben Alex 2004-08-01 07:49:16 +00:00
parent 29f8097c64
commit c1e109da74
8 changed files with 485 additions and 0 deletions

View File

@ -11,6 +11,7 @@ Changes in version 0.6 (2004-xx-xx)
* Added support for EL expressions in the authz tag library
* Added failed Authentication object to AuthenticationExceptions
* Added signed JARs to all official release builds (see readme.txt)
* Added remote client authentication validation package
* Updated Authentication to be serializable (Weblogic support)
* Updated to Clover 1.3
* Updated to HSQLDB version 1.7.2 Release Candidate 6D

View File

@ -0,0 +1,46 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import net.sf.acegisecurity.AcegiSecurityException;
/**
* Thrown if a <code>RemoteAuthenticationManager</code> cannot validate the
* presented authentication request.
*
* <P>
* This is thrown rather than the normal <code>AuthenticationException</code>
* because <code>AuthenticationException</code> contains additional properties
* which may cause issues for the remoting protocol.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RemoteAuthenticationException extends AcegiSecurityException {
//~ Constructors ===========================================================
/**
* Constructs a <code>RemoteAuthenticationException</code> with the
* specified message and no root cause.
*
* @param msg the detail message
*/
public RemoteAuthenticationException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,56 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import net.sf.acegisecurity.GrantedAuthority;
/**
* Allows remote clients to attempt authentication.
*
* @author Ben Alex
* @version $Id$
*/
public interface RemoteAuthenticationManager {
//~ Methods ================================================================
/**
* Attempts to authenticate the remote client using the presented username
* and password. If authentication is successful, an array of
* <code>GrantedAuthority[]</code> objects will be returned.
*
* <P>
* In order to maximise remoting protocol compatibility, a design decision
* was taken to operate with minimal arguments and return only the minimal
* amount information required for remote clients to enable/disable
* relevant user interface commands etc. There is nothing preventing users
* from implementing their own equivalent package that works with more
* complex object types.
* </p>
*
* @param username the username the remote client wishes to authenticate
* with
* @param password the password the remote client wishes to authenticate
* wish
*
* @return all of the granted authorities the specified username and
* password have access to
*
* @throws RemoteAuthenticationException if the authentication failed
*/
public GrantedAuthority[] attemptAuthentication(String username,
String password) throws RemoteAuthenticationException;
}

View File

@ -0,0 +1,73 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.InitializingBean;
/**
* Server-side processor of a remote authentication request.
*
* <P>
* This bean requires no security interceptor to protect it. Instead, the bean
* uses the configured <code>AuthenticationManager</code> to resolve an
* authentication request.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RemoteAuthenticationManagerImpl
implements RemoteAuthenticationManager, InitializingBean {
//~ Instance fields ========================================================
private AuthenticationManager authenticationManager;
//~ Methods ================================================================
public void setAuthenticationManager(
AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
public void afterPropertiesSet() throws Exception {
if (this.authenticationManager == null) {
throw new IllegalArgumentException(
"authenticationManager is required");
}
}
public GrantedAuthority[] attemptAuthentication(String username,
String password) throws RemoteAuthenticationException {
UsernamePasswordAuthenticationToken request = new UsernamePasswordAuthenticationToken(username,
password);
try {
return authenticationManager.authenticate(request).getAuthorities();
} catch (AuthenticationException authEx) {
throw new RemoteAuthenticationException(authEx.getMessage());
}
}
}

View File

@ -0,0 +1,102 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* Client-side object which queries a {@link RemoteAuthenticationManager} to
* validate an authentication request.
*
* <P>
* A new <code>Authentication</code> object is created by this class comprising
* the request <code>Authentication</code> object's <code>principal</code>,
* <code>credentials</code> and the <code>GrantedAuthority</code>[]s returned
* by the <code>RemoteAuthenticationManager</code>.
* </p>
*
* <P>
* The <code>RemoteAuthenticationManager</code> should not require any special
* username or password setting on the remoting client proxy factory to
* execute the call. Instead the entire authentication request must be
* encapsulated solely within the <code>Authentication</code> request object.
* In practical terms this means the <code>RemoteAuthenticationManager</code>
* will <B>not</B> be protected by BASIC or any other HTTP-level
* authentication.
* </p>
*
* <P>
* If authentication fails, a <code>RemoteAuthenticationException</code> will
* be thrown. This exception should be caught and displayed to the user,
* enabling them to retry with alternative credentials etc.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RemoteAuthenticationProvider implements AuthenticationProvider,
InitializingBean {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(RemoteAuthenticationProvider.class);
//~ Instance fields ========================================================
private RemoteAuthenticationManager remoteAuthenticationManager;
//~ Methods ================================================================
public void setRemoteAuthenticationManager(
RemoteAuthenticationManager remoteAuthenticationManager) {
this.remoteAuthenticationManager = remoteAuthenticationManager;
}
public RemoteAuthenticationManager getRemoteAuthenticationManager() {
return remoteAuthenticationManager;
}
public void afterPropertiesSet() throws Exception {
if (this.remoteAuthenticationManager == null) {
throw new IllegalArgumentException(
"remoteAuthenticationManager is mandatory");
}
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getPrincipal().toString();
String password = authentication.getCredentials().toString();
GrantedAuthority[] authorities = remoteAuthenticationManager
.attemptAuthentication(username, password);
return new UsernamePasswordAuthenticationToken(username, password,
authorities);
}
public boolean supports(Class authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
Allows remote clients to authenticate and obtain a populated
<code>Authentication</code> object.
</body>
</html>

View File

@ -0,0 +1,83 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import junit.framework.TestCase;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.MockAuthenticationManager;
/**
* Tests {@link RemoteAuthenticationManagerImpl}.
*
* @author Ben Alex
* @version $Id$
*/
public class RemoteAuthenticationManagerImplTests extends TestCase {
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(RemoteAuthenticationManagerImplTests.class);
}
public void testFailedAuthenticationReturnsRemoteAuthenticationException() {
RemoteAuthenticationManagerImpl manager = new RemoteAuthenticationManagerImpl();
manager.setAuthenticationManager(new MockAuthenticationManager(false));
try {
manager.attemptAuthentication("marissa", "password");
fail("Should have thrown RemoteAuthenticationException");
} catch (RemoteAuthenticationException expected) {
assertTrue(true);
}
}
public void testGettersSetters() {
RemoteAuthenticationManagerImpl manager = new RemoteAuthenticationManagerImpl();
manager.setAuthenticationManager(new MockAuthenticationManager(true));
assertNotNull(manager.getAuthenticationManager());
}
public void testStartupChecksAuthenticationManagerSet()
throws Exception {
RemoteAuthenticationManagerImpl manager = new RemoteAuthenticationManagerImpl();
try {
manager.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
manager.setAuthenticationManager(new MockAuthenticationManager(true));
manager.afterPropertiesSet();
assertTrue(true);
}
public void testSuccessfulAuthentication() {
RemoteAuthenticationManagerImpl manager = new RemoteAuthenticationManagerImpl();
manager.setAuthenticationManager(new MockAuthenticationManager(true));
GrantedAuthority[] result = manager.attemptAuthentication("marissa",
"password");
assertTrue(true);
}
}

View File

@ -0,0 +1,117 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.rcp;
import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
/**
* Tests {@link RemoteAuthenticationProvider}.
*
* @author Ben Alex
* @version $Id$
*/
public class RemoteAuthenticationProviderTests extends TestCase {
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(RemoteAuthenticationProviderTests.class);
}
public void testExceptionsGetPassedBackToCaller() {
RemoteAuthenticationProvider provider = new RemoteAuthenticationProvider();
provider.setRemoteAuthenticationManager(new MockRemoteAuthenticationManager(
false));
try {
provider.authenticate(new UsernamePasswordAuthenticationToken(
"marissa", "password"));
fail("Should have thrown RemoteAuthenticationException");
} catch (RemoteAuthenticationException expected) {
assertTrue(true);
}
}
public void testGettersSetters() {
RemoteAuthenticationProvider provider = new RemoteAuthenticationProvider();
provider.setRemoteAuthenticationManager(new MockRemoteAuthenticationManager(
true));
assertNotNull(provider.getRemoteAuthenticationManager());
}
public void testStartupChecksAuthenticationManagerSet()
throws Exception {
RemoteAuthenticationProvider provider = new RemoteAuthenticationProvider();
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
provider.setRemoteAuthenticationManager(new MockRemoteAuthenticationManager(
true));
provider.afterPropertiesSet();
assertTrue(true);
}
public void testSuccessfulAuthenticationCreatesObject() {
RemoteAuthenticationProvider provider = new RemoteAuthenticationProvider();
provider.setRemoteAuthenticationManager(new MockRemoteAuthenticationManager(
true));
Authentication result = provider.authenticate(new UsernamePasswordAuthenticationToken(
"marissa", "password"));
assertEquals("marissa", result.getPrincipal());
assertEquals("password", result.getCredentials());
assertEquals("foo", result.getAuthorities()[0].getAuthority());
}
public void testSupports() {
RemoteAuthenticationProvider provider = new RemoteAuthenticationProvider();
assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
}
//~ Inner Classes ==========================================================
private class MockRemoteAuthenticationManager
implements RemoteAuthenticationManager {
private boolean grantAccess;
public MockRemoteAuthenticationManager(boolean grantAccess) {
this.grantAccess = grantAccess;
}
public GrantedAuthority[] attemptAuthentication(String username,
String password) throws RemoteAuthenticationException {
if (grantAccess) {
return new GrantedAuthority[] {new GrantedAuthorityImpl("foo")};
} else {
throw new RemoteAuthenticationException("as requested");
}
}
}
}