You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ad...@apache.org on 2005/02/16 20:48:06 UTC

svn commit: r154075 - in geronimo/trunk/modules/security/src: java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java

Author: adc
Date: Wed Feb 16 11:48:03 2005
New Revision: 154075

URL: http://svn.apache.org/viewcvs?view=rev&rev=154075
Log:
Simple login module that scrapes the username/password and places the information into a private credential.

Added:
    geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java
    geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java
Modified:
    geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java

Added: geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java?view=auto&rev=154075
==============================================================================
--- geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java (added)
+++ geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java Wed Feb 16 11:48:03 2005
@@ -0,0 +1,108 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ *  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 org.apache.geronimo.security.jaas;
+
+import java.io.IOException;
+import java.util.Map;
+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.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+
+/**
+ * Inserts Username/Password credential into private credentials of Subject.
+ * <p/>
+ * If either the username or password is not passed in the callback handler,
+ * then the credential is not placed into the Subject.
+ *
+ * @version $Revision: $ $Date: $
+ */
+public class UPCredentialLoginModule implements LoginModule {
+
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private UsernamePasswordCredential upCredential;
+
+    public boolean abort() throws LoginException {
+
+        return logout();
+    }
+
+    public boolean commit() throws LoginException {
+
+        if (subject.isReadOnly()) {
+            throw new LoginException("Subject is ReadOnly");
+        }
+
+        Set pvtCreds = subject.getPrivateCredentials();
+        if (upCredential != null && !pvtCreds.contains(upCredential)) {
+            pvtCreds.add(upCredential);
+        }
+
+        return true;
+    }
+
+    public boolean login() throws LoginException {
+
+        Callback[] callbacks = new Callback[2];
+
+        callbacks[0] = new NameCallback("User name");
+        callbacks[1] = new PasswordCallback("Password", false);
+        try {
+            callbackHandler.handle(callbacks);
+        } catch (IOException ioe) {
+            throw (LoginException) new LoginException().initCause(ioe);
+        } catch (UnsupportedCallbackException uce) {
+            throw (LoginException) new LoginException().initCause(uce);
+        }
+
+        String username = ((NameCallback) callbacks[0]).getName();
+        char[] password = ((PasswordCallback) callbacks[1]).getPassword();
+
+        if (username == null || password == null) return true;
+
+        upCredential = new UsernamePasswordCredential(username, new String(password));
+
+        return true;
+    }
+
+    public boolean logout() throws LoginException {
+
+        if (upCredential == null) return true;
+
+        Set pvtCreds = subject.getPrivateCredentials(UsernamePasswordCredential.class);
+        if (pvtCreds.contains(upCredential)) {
+            pvtCreds.remove(upCredential);
+        }
+
+        upCredential = null;
+
+        return true;
+    }
+
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
+
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+    }
+}

Added: geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java?view=auto&rev=154075
==============================================================================
--- geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java (added)
+++ geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java Wed Feb 16 11:48:03 2005
@@ -0,0 +1,91 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation
+ *
+ *  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 org.apache.geronimo.security.jaas;
+
+import java.io.Serializable;
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Destroyable;
+import javax.security.auth.RefreshFailedException;
+import javax.security.auth.Refreshable;
+
+
+/**
+ * A username/password credential.  Used to store the username/password in the
+ * Subject's private credentials.
+ *
+ * @version $Revision: $ $Date: $
+ */
+public class UsernamePasswordCredential implements Destroyable, Refreshable, Serializable {
+
+    private String username;
+    private String password;
+    private boolean destroyed;
+
+    public UsernamePasswordCredential(String username, String password) {
+        assert username != null;
+        assert password != null;
+
+        this.username = username;
+        this.password = password;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void destroy() throws DestroyFailedException {
+        username = null;
+        password = null;
+        destroyed = true;
+    }
+
+    public boolean isDestroyed() {
+        return destroyed;
+    }
+
+    public void refresh() throws RefreshFailedException {
+    }
+
+    public boolean isCurrent() {
+        return !destroyed;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof UsernamePasswordCredential)) return false;
+
+        final UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) o;
+
+        if (destroyed != usernamePasswordCredential.destroyed) return false;
+        if (!password.equals(usernamePasswordCredential.password)) return false;
+        if (!username.equals(usernamePasswordCredential.username)) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = username.hashCode();
+        result = 29 * result + password.hashCode();
+        result = 29 * result + (destroyed ? 1 : 0);
+        return result;
+    }
+}

Modified: geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java?view=diff&r1=154074&r2=154075
==============================================================================
--- geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java (original)
+++ geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java Wed Feb 16 11:48:03 2005
@@ -48,6 +48,7 @@
     protected ObjectName loginConfiguration;
     protected ObjectName loginService;
     protected ObjectName clientCE;
+    protected ObjectName testUPCred;
     protected ObjectName testCE;
     protected ObjectName testRealm;
     protected ObjectName serverStub;
@@ -79,6 +80,7 @@
         assertTrue("server subject should be associated with remote id", ContextManager.getRegisteredSubject(remote.getId()) != null);
         assertTrue("server subject should have two realm principals ("+subject.getPrincipals(RealmPrincipal.class).size()+")", subject.getPrincipals(RealmPrincipal.class).size() == 2);
         assertTrue("server subject should have five principals ("+subject.getPrincipals().size()+")", subject.getPrincipals().size() == 5);
+        assertTrue("server subject should have one private credential ("+subject.getPrivateCredentials().size()+")", subject.getPrivateCredentials().size() == 1);
         RealmPrincipal principal = (RealmPrincipal) subject.getPrincipals(RealmPrincipal.class).iterator().next();
         assertTrue("id of principal should be non-zero", principal.getId() != 0);
 
@@ -108,6 +110,7 @@
         assertTrue("server subject should be associated with remote id", ContextManager.getRegisteredSubject(remote.getId()) != null);
         assertTrue("server subject should have two realm principals ("+subject.getPrincipals(RealmPrincipal.class).size()+")", subject.getPrincipals(RealmPrincipal.class).size() == 2);
         assertTrue("server subject should have five principals ("+subject.getPrincipals().size()+")", subject.getPrincipals().size() == 5);
+        assertTrue("server subject should have one private credential ("+subject.getPrivateCredentials().size()+")", subject.getPrivateCredentials().size() == 1);
         principal = (RealmPrincipal) subject.getPrincipals(RealmPrincipal.class).iterator().next();
         assertTrue("id of principal should be non-zero", principal.getId() != 0);
 
@@ -166,6 +169,13 @@
         kernel.loadGBean(testCE, gbean);
 
         gbean = new GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
+        testUPCred = new ObjectName("geronimo.security:type=LoginModule,name=UPCred");
+        gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.jaas.UPCredentialLoginModule");
+        gbean.setAttribute("serverSide", new Boolean(true));
+        gbean.setAttribute("options", new Properties());
+        kernel.loadGBean(testUPCred, gbean);
+
+        gbean = new GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
         testCE = new ObjectName("geronimo.security:type=LoginModule,name=audit");
         gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.FileAuditLoginModule");
         gbean.setAttribute("serverSide", new Boolean(true));
@@ -178,7 +188,8 @@
         testRealm = new ObjectName("geronimo.security:type=SecurityRealm,realm=properties-realm");
         gbean.setAttribute("realmName", "properties-realm");
         props = new Properties();
-        props.setProperty("LoginModule.2.OPTIONAL","geronimo.security:type=LoginModule,name=audit");
+        props.setProperty("LoginModule.3.REQUIRED","geronimo.security:type=LoginModule,name=UPCred");
+        props.setProperty("LoginModule.2.REQUIRED","geronimo.security:type=LoginModule,name=audit");
         props.setProperty("LoginModule.1.REQUIRED","geronimo.security:type=LoginModule,name=properties");
         gbean.setAttribute("loginModuleConfiguration", props);
         gbean.setReferencePatterns("ServerInfo", Collections.singleton(serverInfo));
@@ -194,6 +205,7 @@
         kernel.startGBean(loginService);
         kernel.startGBean(clientCE);
         kernel.startGBean(testCE);
+        kernel.startGBean(testUPCred);
         kernel.startGBean(testRealm);
         kernel.startGBean(serverStub);
     }
@@ -201,6 +213,7 @@
     protected void tearDown() throws Exception {
         kernel.stopGBean(serverStub);
         kernel.stopGBean(testRealm);
+        kernel.stopGBean(testUPCred);
         kernel.stopGBean(testCE);
         kernel.stopGBean(clientCE);
         kernel.stopGBean(loginService);
@@ -209,6 +222,7 @@
 
         kernel.unloadGBean(loginService);
         kernel.unloadGBean(testCE);
+        kernel.unloadGBean(testUPCred);
         kernel.unloadGBean(testRealm);
         kernel.unloadGBean(clientCE);
         kernel.unloadGBean(serverStub);



Re: svn commit: r154075 - in geronimo/trunk/modules/security/src: java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java

Posted by "Alan D. Cabrera" <ad...@toolazydogs.com>.
Thanks for the hads-up.  I fixed the bug and included the security 
enhancement that you suggested on IRC, blanking out the pw when destroying.


Regards,
Alan

David Jencks wrote:

> There are a couple problems with this:
>
> 1. it essentially duplicates the intended functionality of the 
> existing  o.a.g.security.realm.GeronimoPasswordCredential/LoginModule
>
> 2. The inclusion of the destroy method and implementation breaks the  
> contracts for equals and hashcode for use in a Collection.  In other  
> words, after destroying UserPasswordCredential you won't be able to  
> remove it from a collection.  I think throwing an 
> IllegalStateException  from equals and hashcode after destroy might be 
> reasonable.  Currently,  calling hashCode after destroy will have 
> undesirable effects (npe)
>
> I propose we fix the equals/hashcode problem somehow and replace the  
> use of GeronimoPasswordCredential[LoginModule] with the new classes.
>
> thanks
> david jencks
>
> On Feb 16, 2005, at 11:48 AM, adc@apache.org wrote:
>
>> Author: adc
>> Date: Wed Feb 16 11:48:03 2005
>> New Revision: 154075
>>
>> URL: http://svn.apache.org/viewcvs?view=rev&rev=154075
>> Log:
>> Simple login module that scrapes the username/password and places 
>> the  information into a private credential.
>>
>> Added:
>>      
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UPCredentialLoginModule.java
>>      
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UsernamePasswordCredential.java
>> Modified:
>>      
>> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
>> jaas/ConfigurationEntryTest.java
>>
>> Added:  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UPCredentialLoginModule.java
>> URL:  
>> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
>> java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java? 
>> view=auto&rev=154075
>> ======================================================================= 
>> =======
>> ---  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UPCredentialLoginModule.java (added)
>> +++  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UPCredentialLoginModule.java Wed Feb 16 11:48:03 2005
>> @@ -0,0 +1,108 @@
>> +/**
>> + *
>> + * Copyright 2005 The Apache Software Foundation
>> + *
>> + *  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 org.apache.geronimo.security.jaas;
>> +
>> +import java.io.IOException;
>> +import java.util.Map;
>> +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.LoginException;
>> +import javax.security.auth.spi.LoginModule;
>> +
>> +
>> +/**
>> + * Inserts Username/Password credential into private credentials of  
>> Subject.
>> + * <p/>
>> + * If either the username or password is not passed in the callback  
>> handler,
>> + * then the credential is not placed into the Subject.
>> + *
>> + * @version $Revision: $ $Date: $
>> + */
>> +public class UPCredentialLoginModule implements LoginModule {
>> +
>> +    private Subject subject;
>> +    private CallbackHandler callbackHandler;
>> +    private UsernamePasswordCredential upCredential;
>> +
>> +    public boolean abort() throws LoginException {
>> +
>> +        return logout();
>> +    }
>> +
>> +    public boolean commit() throws LoginException {
>> +
>> +        if (subject.isReadOnly()) {
>> +            throw new LoginException("Subject is ReadOnly");
>> +        }
>> +
>> +        Set pvtCreds = subject.getPrivateCredentials();
>> +        if (upCredential != null && 
>> !pvtCreds.contains(upCredential))  {
>> +            pvtCreds.add(upCredential);
>> +        }
>> +
>> +        return true;
>> +    }
>> +
>> +    public boolean login() throws LoginException {
>> +
>> +        Callback[] callbacks = new Callback[2];
>> +
>> +        callbacks[0] = new NameCallback("User name");
>> +        callbacks[1] = new PasswordCallback("Password", false);
>> +        try {
>> +            callbackHandler.handle(callbacks);
>> +        } catch (IOException ioe) {
>> +            throw (LoginException) new  
>> LoginException().initCause(ioe);
>> +        } catch (UnsupportedCallbackException uce) {
>> +            throw (LoginException) new  
>> LoginException().initCause(uce);
>> +        }
>> +
>> +        String username = ((NameCallback) callbacks[0]).getName();
>> +        char[] password = ((PasswordCallback)  
>> callbacks[1]).getPassword();
>> +
>> +        if (username == null || password == null) return true;
>> +
>> +        upCredential = new UsernamePasswordCredential(username, new  
>> String(password));
>> +
>> +        return true;
>> +    }
>> +
>> +    public boolean logout() throws LoginException {
>> +
>> +        if (upCredential == null) return true;
>> +
>> +        Set pvtCreds =  
>> subject.getPrivateCredentials(UsernamePasswordCredential.class);
>> +        if (pvtCreds.contains(upCredential)) {
>> +            pvtCreds.remove(upCredential);
>> +        }
>> +
>> +        upCredential = null;
>> +
>> +        return true;
>> +    }
>> +
>> +    public void initialize(Subject subject, CallbackHandler  
>> callbackHandler, Map sharedState, Map options) {
>> +
>> +        this.subject = subject;
>> +        this.callbackHandler = callbackHandler;
>> +    }
>> +}
>>
>> Added:  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UsernamePasswordCredential.java
>> URL:  
>> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
>> java/org/apache/geronimo/security/jaas/ 
>> UsernamePasswordCredential.java?view=auto&rev=154075
>> ======================================================================= 
>> =======
>> ---  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UsernamePasswordCredential.java (added)
>> +++  
>> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
>> jaas/UsernamePasswordCredential.java Wed Feb 16 11:48:03 2005
>> @@ -0,0 +1,91 @@
>> +/**
>> + *
>> + * Copyright 2005 The Apache Software Foundation
>> + *
>> + *  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 org.apache.geronimo.security.jaas;
>> +
>> +import java.io.Serializable;
>> +import javax.security.auth.DestroyFailedException;
>> +import javax.security.auth.Destroyable;
>> +import javax.security.auth.RefreshFailedException;
>> +import javax.security.auth.Refreshable;
>> +
>> +
>> +/**
>> + * A username/password credential.  Used to store the  
>> username/password in the
>> + * Subject's private credentials.
>> + *
>> + * @version $Revision: $ $Date: $
>> + */
>> +public class UsernamePasswordCredential implements Destroyable,  
>> Refreshable, Serializable {
>> +
>> +    private String username;
>> +    private String password;
>> +    private boolean destroyed;
>> +
>> +    public UsernamePasswordCredential(String username, String  
>> password) {
>> +        assert username != null;
>> +        assert password != null;
>> +
>> +        this.username = username;
>> +        this.password = password;
>> +    }
>> +
>> +    public String getUsername() {
>> +        return username;
>> +    }
>> +
>> +    public String getPassword() {
>> +        return password;
>> +    }
>> +
>> +    public void destroy() throws DestroyFailedException {
>> +        username = null;
>> +        password = null;
>> +        destroyed = true;
>> +    }
>> +
>> +    public boolean isDestroyed() {
>> +        return destroyed;
>> +    }
>> +
>> +    public void refresh() throws RefreshFailedException {
>> +    }
>> +
>> +    public boolean isCurrent() {
>> +        return !destroyed;
>> +    }
>> +
>> +    public boolean equals(Object o) {
>> +        if (this == o) return true;
>> +        if (!(o instanceof UsernamePasswordCredential)) return false;
>> +
>> +        final UsernamePasswordCredential usernamePasswordCredential 
>> =  (UsernamePasswordCredential) o;
>> +
>> +        if (destroyed != usernamePasswordCredential.destroyed) 
>> return  false;
>> +        if (!password.equals(usernamePasswordCredential.password))  
>> return false;
>> +        if (!username.equals(usernamePasswordCredential.username))  
>> return false;
>> +
>> +        return true;
>> +    }
>> +
>> +    public int hashCode() {
>> +        int result;
>> +        result = username.hashCode();
>> +        result = 29 * result + password.hashCode();
>> +        result = 29 * result + (destroyed ? 1 : 0);
>> +        return result;
>> +    }
>> +}
>>
>> Modified:  
>> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
>> jaas/ConfigurationEntryTest.java
>> URL:  
>> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
>> test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java? 
>> view=diff&r1=154074&r2=154075
>> ======================================================================= 
>> =======
>> ---  
>> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
>> jaas/ConfigurationEntryTest.java (original)
>> +++  
>> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
>> jaas/ConfigurationEntryTest.java Wed Feb 16 11:48:03 2005
>> @@ -48,6 +48,7 @@
>>      protected ObjectName loginConfiguration;
>>      protected ObjectName loginService;
>>      protected ObjectName clientCE;
>> +    protected ObjectName testUPCred;
>>      protected ObjectName testCE;
>>      protected ObjectName testRealm;
>>      protected ObjectName serverStub;
>> @@ -79,6 +80,7 @@
>>          assertTrue("server subject should be associated with remote  
>> id", ContextManager.getRegisteredSubject(remote.getId()) != null);
>>          assertTrue("server subject should have two realm principals  
>> ("+subject.getPrincipals(RealmPrincipal.class).size()+")",  
>> subject.getPrincipals(RealmPrincipal.class).size() == 2);
>>          assertTrue("server subject should have five principals  
>> ("+subject.getPrincipals().size()+")", 
>> subject.getPrincipals().size()  == 5);
>> +        assertTrue("server subject should have one private 
>> credential  ("+subject.getPrivateCredentials().size()+")",  
>> subject.getPrivateCredentials().size() == 1);
>>          RealmPrincipal principal = (RealmPrincipal)  
>> subject.getPrincipals(RealmPrincipal.class).iterator().next();
>>          assertTrue("id of principal should be non-zero",  
>> principal.getId() != 0);
>>
>> @@ -108,6 +110,7 @@
>>          assertTrue("server subject should be associated with remote  
>> id", ContextManager.getRegisteredSubject(remote.getId()) != null);
>>          assertTrue("server subject should have two realm principals  
>> ("+subject.getPrincipals(RealmPrincipal.class).size()+")",  
>> subject.getPrincipals(RealmPrincipal.class).size() == 2);
>>          assertTrue("server subject should have five principals  
>> ("+subject.getPrincipals().size()+")", 
>> subject.getPrincipals().size()  == 5);
>> +        assertTrue("server subject should have one private 
>> credential  ("+subject.getPrivateCredentials().size()+")",  
>> subject.getPrivateCredentials().size() == 1);
>>          principal = (RealmPrincipal)  
>> subject.getPrincipals(RealmPrincipal.class).iterator().next();
>>          assertTrue("id of principal should be non-zero",  
>> principal.getId() != 0);
>>
>> @@ -166,6 +169,13 @@
>>          kernel.loadGBean(testCE, gbean);
>>
>>          gbean = new  
>> GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
>> +        testUPCred = new  
>> ObjectName("geronimo.security:type=LoginModule,name=UPCred");
>> +        gbean.setAttribute("loginModuleClass",  
>> "org.apache.geronimo.security.jaas.UPCredentialLoginModule");
>> +        gbean.setAttribute("serverSide", new Boolean(true));
>> +        gbean.setAttribute("options", new Properties());
>> +        kernel.loadGBean(testUPCred, gbean);
>> +
>> +        gbean = new  
>> GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
>>          testCE = new  
>> ObjectName("geronimo.security:type=LoginModule,name=audit");
>>          gbean.setAttribute("loginModuleClass",  
>> "org.apache.geronimo.security.realm.providers.FileAuditLoginModule");
>>          gbean.setAttribute("serverSide", new Boolean(true));
>> @@ -178,7 +188,8 @@
>>          testRealm = new  
>> ObjectName("geronimo.security:type=SecurityRealm,realm=properties- 
>> realm");
>>          gbean.setAttribute("realmName", "properties-realm");
>>          props = new Properties();
>> -         
>> props.setProperty("LoginModule.2.OPTIONAL","geronimo.security: 
>> type=LoginModule,name=audit");
>> +         
>> props.setProperty("LoginModule.3.REQUIRED","geronimo.security: 
>> type=LoginModule,name=UPCred");
>> +         
>> props.setProperty("LoginModule.2.REQUIRED","geronimo.security: 
>> type=LoginModule,name=audit");
>>           
>> props.setProperty("LoginModule.1.REQUIRED","geronimo.security: 
>> type=LoginModule,name=properties");
>>          gbean.setAttribute("loginModuleConfiguration", props);
>>          gbean.setReferencePatterns("ServerInfo",  
>> Collections.singleton(serverInfo));
>> @@ -194,6 +205,7 @@
>>          kernel.startGBean(loginService);
>>          kernel.startGBean(clientCE);
>>          kernel.startGBean(testCE);
>> +        kernel.startGBean(testUPCred);
>>          kernel.startGBean(testRealm);
>>          kernel.startGBean(serverStub);
>>      }
>> @@ -201,6 +213,7 @@
>>      protected void tearDown() throws Exception {
>>          kernel.stopGBean(serverStub);
>>          kernel.stopGBean(testRealm);
>> +        kernel.stopGBean(testUPCred);
>>          kernel.stopGBean(testCE);
>>          kernel.stopGBean(clientCE);
>>          kernel.stopGBean(loginService);
>> @@ -209,6 +222,7 @@
>>
>>          kernel.unloadGBean(loginService);
>>          kernel.unloadGBean(testCE);
>> +        kernel.unloadGBean(testUPCred);
>>          kernel.unloadGBean(testRealm);
>>          kernel.unloadGBean(clientCE);
>>          kernel.unloadGBean(serverStub);
>>
>>


Re: svn commit: r154075 - in geronimo/trunk/modules/security/src: java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java java/org/apache/geronimo/security/jaas/UsernamePasswordCredential.java test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java

Posted by David Jencks <dj...@gluecode.com>.
There are a couple problems with this:

1. it essentially duplicates the intended functionality of the existing  
o.a.g.security.realm.GeronimoPasswordCredential/LoginModule

2. The inclusion of the destroy method and implementation breaks the  
contracts for equals and hashcode for use in a Collection.  In other  
words, after destroying UserPasswordCredential you won't be able to  
remove it from a collection.  I think throwing an IllegalStateException  
from equals and hashcode after destroy might be reasonable.  Currently,  
calling hashCode after destroy will have undesirable effects (npe)

I propose we fix the equals/hashcode problem somehow and replace the  
use of GeronimoPasswordCredential[LoginModule] with the new classes.

thanks
david jencks

On Feb 16, 2005, at 11:48 AM, adc@apache.org wrote:

> Author: adc
> Date: Wed Feb 16 11:48:03 2005
> New Revision: 154075
>
> URL: http://svn.apache.org/viewcvs?view=rev&rev=154075
> Log:
> Simple login module that scrapes the username/password and places the  
> information into a private credential.
>
> Added:
>      
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UPCredentialLoginModule.java
>      
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UsernamePasswordCredential.java
> Modified:
>      
> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
> jaas/ConfigurationEntryTest.java
>
> Added:  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UPCredentialLoginModule.java
> URL:  
> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
> java/org/apache/geronimo/security/jaas/UPCredentialLoginModule.java? 
> view=auto&rev=154075
> ======================================================================= 
> =======
> ---  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UPCredentialLoginModule.java (added)
> +++  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UPCredentialLoginModule.java Wed Feb 16 11:48:03 2005
> @@ -0,0 +1,108 @@
> +/**
> + *
> + * Copyright 2005 The Apache Software Foundation
> + *
> + *  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 org.apache.geronimo.security.jaas;
> +
> +import java.io.IOException;
> +import java.util.Map;
> +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.LoginException;
> +import javax.security.auth.spi.LoginModule;
> +
> +
> +/**
> + * Inserts Username/Password credential into private credentials of  
> Subject.
> + * <p/>
> + * If either the username or password is not passed in the callback  
> handler,
> + * then the credential is not placed into the Subject.
> + *
> + * @version $Revision: $ $Date: $
> + */
> +public class UPCredentialLoginModule implements LoginModule {
> +
> +    private Subject subject;
> +    private CallbackHandler callbackHandler;
> +    private UsernamePasswordCredential upCredential;
> +
> +    public boolean abort() throws LoginException {
> +
> +        return logout();
> +    }
> +
> +    public boolean commit() throws LoginException {
> +
> +        if (subject.isReadOnly()) {
> +            throw new LoginException("Subject is ReadOnly");
> +        }
> +
> +        Set pvtCreds = subject.getPrivateCredentials();
> +        if (upCredential != null && !pvtCreds.contains(upCredential))  
> {
> +            pvtCreds.add(upCredential);
> +        }
> +
> +        return true;
> +    }
> +
> +    public boolean login() throws LoginException {
> +
> +        Callback[] callbacks = new Callback[2];
> +
> +        callbacks[0] = new NameCallback("User name");
> +        callbacks[1] = new PasswordCallback("Password", false);
> +        try {
> +            callbackHandler.handle(callbacks);
> +        } catch (IOException ioe) {
> +            throw (LoginException) new  
> LoginException().initCause(ioe);
> +        } catch (UnsupportedCallbackException uce) {
> +            throw (LoginException) new  
> LoginException().initCause(uce);
> +        }
> +
> +        String username = ((NameCallback) callbacks[0]).getName();
> +        char[] password = ((PasswordCallback)  
> callbacks[1]).getPassword();
> +
> +        if (username == null || password == null) return true;
> +
> +        upCredential = new UsernamePasswordCredential(username, new  
> String(password));
> +
> +        return true;
> +    }
> +
> +    public boolean logout() throws LoginException {
> +
> +        if (upCredential == null) return true;
> +
> +        Set pvtCreds =  
> subject.getPrivateCredentials(UsernamePasswordCredential.class);
> +        if (pvtCreds.contains(upCredential)) {
> +            pvtCreds.remove(upCredential);
> +        }
> +
> +        upCredential = null;
> +
> +        return true;
> +    }
> +
> +    public void initialize(Subject subject, CallbackHandler  
> callbackHandler, Map sharedState, Map options) {
> +
> +        this.subject = subject;
> +        this.callbackHandler = callbackHandler;
> +    }
> +}
>
> Added:  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UsernamePasswordCredential.java
> URL:  
> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
> java/org/apache/geronimo/security/jaas/ 
> UsernamePasswordCredential.java?view=auto&rev=154075
> ======================================================================= 
> =======
> ---  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UsernamePasswordCredential.java (added)
> +++  
> geronimo/trunk/modules/security/src/java/org/apache/geronimo/security/ 
> jaas/UsernamePasswordCredential.java Wed Feb 16 11:48:03 2005
> @@ -0,0 +1,91 @@
> +/**
> + *
> + * Copyright 2005 The Apache Software Foundation
> + *
> + *  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 org.apache.geronimo.security.jaas;
> +
> +import java.io.Serializable;
> +import javax.security.auth.DestroyFailedException;
> +import javax.security.auth.Destroyable;
> +import javax.security.auth.RefreshFailedException;
> +import javax.security.auth.Refreshable;
> +
> +
> +/**
> + * A username/password credential.  Used to store the  
> username/password in the
> + * Subject's private credentials.
> + *
> + * @version $Revision: $ $Date: $
> + */
> +public class UsernamePasswordCredential implements Destroyable,  
> Refreshable, Serializable {
> +
> +    private String username;
> +    private String password;
> +    private boolean destroyed;
> +
> +    public UsernamePasswordCredential(String username, String  
> password) {
> +        assert username != null;
> +        assert password != null;
> +
> +        this.username = username;
> +        this.password = password;
> +    }
> +
> +    public String getUsername() {
> +        return username;
> +    }
> +
> +    public String getPassword() {
> +        return password;
> +    }
> +
> +    public void destroy() throws DestroyFailedException {
> +        username = null;
> +        password = null;
> +        destroyed = true;
> +    }
> +
> +    public boolean isDestroyed() {
> +        return destroyed;
> +    }
> +
> +    public void refresh() throws RefreshFailedException {
> +    }
> +
> +    public boolean isCurrent() {
> +        return !destroyed;
> +    }
> +
> +    public boolean equals(Object o) {
> +        if (this == o) return true;
> +        if (!(o instanceof UsernamePasswordCredential)) return false;
> +
> +        final UsernamePasswordCredential usernamePasswordCredential =  
> (UsernamePasswordCredential) o;
> +
> +        if (destroyed != usernamePasswordCredential.destroyed) return  
> false;
> +        if (!password.equals(usernamePasswordCredential.password))  
> return false;
> +        if (!username.equals(usernamePasswordCredential.username))  
> return false;
> +
> +        return true;
> +    }
> +
> +    public int hashCode() {
> +        int result;
> +        result = username.hashCode();
> +        result = 29 * result + password.hashCode();
> +        result = 29 * result + (destroyed ? 1 : 0);
> +        return result;
> +    }
> +}
>
> Modified:  
> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
> jaas/ConfigurationEntryTest.java
> URL:  
> http://svn.apache.org/viewcvs/geronimo/trunk/modules/security/src/ 
> test/org/apache/geronimo/security/jaas/ConfigurationEntryTest.java? 
> view=diff&r1=154074&r2=154075
> ======================================================================= 
> =======
> ---  
> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
> jaas/ConfigurationEntryTest.java (original)
> +++  
> geronimo/trunk/modules/security/src/test/org/apache/geronimo/security/ 
> jaas/ConfigurationEntryTest.java Wed Feb 16 11:48:03 2005
> @@ -48,6 +48,7 @@
>      protected ObjectName loginConfiguration;
>      protected ObjectName loginService;
>      protected ObjectName clientCE;
> +    protected ObjectName testUPCred;
>      protected ObjectName testCE;
>      protected ObjectName testRealm;
>      protected ObjectName serverStub;
> @@ -79,6 +80,7 @@
>          assertTrue("server subject should be associated with remote  
> id", ContextManager.getRegisteredSubject(remote.getId()) != null);
>          assertTrue("server subject should have two realm principals  
> ("+subject.getPrincipals(RealmPrincipal.class).size()+")",  
> subject.getPrincipals(RealmPrincipal.class).size() == 2);
>          assertTrue("server subject should have five principals  
> ("+subject.getPrincipals().size()+")", subject.getPrincipals().size()  
> == 5);
> +        assertTrue("server subject should have one private credential  
> ("+subject.getPrivateCredentials().size()+")",  
> subject.getPrivateCredentials().size() == 1);
>          RealmPrincipal principal = (RealmPrincipal)  
> subject.getPrincipals(RealmPrincipal.class).iterator().next();
>          assertTrue("id of principal should be non-zero",  
> principal.getId() != 0);
>
> @@ -108,6 +110,7 @@
>          assertTrue("server subject should be associated with remote  
> id", ContextManager.getRegisteredSubject(remote.getId()) != null);
>          assertTrue("server subject should have two realm principals  
> ("+subject.getPrincipals(RealmPrincipal.class).size()+")",  
> subject.getPrincipals(RealmPrincipal.class).size() == 2);
>          assertTrue("server subject should have five principals  
> ("+subject.getPrincipals().size()+")", subject.getPrincipals().size()  
> == 5);
> +        assertTrue("server subject should have one private credential  
> ("+subject.getPrivateCredentials().size()+")",  
> subject.getPrivateCredentials().size() == 1);
>          principal = (RealmPrincipal)  
> subject.getPrincipals(RealmPrincipal.class).iterator().next();
>          assertTrue("id of principal should be non-zero",  
> principal.getId() != 0);
>
> @@ -166,6 +169,13 @@
>          kernel.loadGBean(testCE, gbean);
>
>          gbean = new  
> GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
> +        testUPCred = new  
> ObjectName("geronimo.security:type=LoginModule,name=UPCred");
> +        gbean.setAttribute("loginModuleClass",  
> "org.apache.geronimo.security.jaas.UPCredentialLoginModule");
> +        gbean.setAttribute("serverSide", new Boolean(true));
> +        gbean.setAttribute("options", new Properties());
> +        kernel.loadGBean(testUPCred, gbean);
> +
> +        gbean = new  
> GBeanMBean("org.apache.geronimo.security.jaas.LoginModuleGBean");
>          testCE = new  
> ObjectName("geronimo.security:type=LoginModule,name=audit");
>          gbean.setAttribute("loginModuleClass",  
> "org.apache.geronimo.security.realm.providers.FileAuditLoginModule");
>          gbean.setAttribute("serverSide", new Boolean(true));
> @@ -178,7 +188,8 @@
>          testRealm = new  
> ObjectName("geronimo.security:type=SecurityRealm,realm=properties- 
> realm");
>          gbean.setAttribute("realmName", "properties-realm");
>          props = new Properties();
> -         
> props.setProperty("LoginModule.2.OPTIONAL","geronimo.security: 
> type=LoginModule,name=audit");
> +         
> props.setProperty("LoginModule.3.REQUIRED","geronimo.security: 
> type=LoginModule,name=UPCred");
> +         
> props.setProperty("LoginModule.2.REQUIRED","geronimo.security: 
> type=LoginModule,name=audit");
>           
> props.setProperty("LoginModule.1.REQUIRED","geronimo.security: 
> type=LoginModule,name=properties");
>          gbean.setAttribute("loginModuleConfiguration", props);
>          gbean.setReferencePatterns("ServerInfo",  
> Collections.singleton(serverInfo));
> @@ -194,6 +205,7 @@
>          kernel.startGBean(loginService);
>          kernel.startGBean(clientCE);
>          kernel.startGBean(testCE);
> +        kernel.startGBean(testUPCred);
>          kernel.startGBean(testRealm);
>          kernel.startGBean(serverStub);
>      }
> @@ -201,6 +213,7 @@
>      protected void tearDown() throws Exception {
>          kernel.stopGBean(serverStub);
>          kernel.stopGBean(testRealm);
> +        kernel.stopGBean(testUPCred);
>          kernel.stopGBean(testCE);
>          kernel.stopGBean(clientCE);
>          kernel.stopGBean(loginService);
> @@ -209,6 +222,7 @@
>
>          kernel.unloadGBean(loginService);
>          kernel.unloadGBean(testCE);
> +        kernel.unloadGBean(testUPCred);
>          kernel.unloadGBean(testRealm);
>          kernel.unloadGBean(clientCE);
>          kernel.unloadGBean(serverStub);
>
>