Author: angela Date: Wed Oct 31 19:28:20 2012 New Revision: 1404313 URL: http://svn.apache.org/viewvc?rev=1404313&view=rev Log: OAK-91 - Implement Authentication Support (WIP)
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/AbstractTokenTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenAuthenticationTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthenticationTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthentication.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenInfoTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java?rev=1404313&r1=1404312&r2=1404313&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java Wed Oct 31 19:28:20 2012 @@ -172,6 +172,7 @@ public class TokenProviderImpl implement String tokenName = Text.replace(ISO8601.format(creation), ":", "."); NodeUtil tokenNode = tokenParent.addChild(tokenName, TOKENS_NT_NAME); + // TODO: review if token node should be made referenceable String key = generateKey(options.getConfigValue(PARAM_TOKEN_LENGTH, DEFAULT_KEY_SIZE)); String nodeId = identifierManager.getIdentifier(tokenNode.getTree()); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthentication.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthentication.java?rev=1404313&r1=1404312&r2=1404313&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthentication.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthentication.java Wed Oct 31 19:28:20 2012 @@ -74,7 +74,7 @@ class UserAuthentication implements Auth return false; } - boolean success; + boolean success = false; try { Authorizable authorizable = userManager.getAuthorizable(userId); if (authorizable == null || authorizable.isGroup()) { @@ -89,15 +89,14 @@ class UserAuthentication implements Auth if (credentials instanceof SimpleCredentials) { SimpleCredentials creds = (SimpleCredentials) credentials; Credentials userCreds = user.getCredentials(); - if (userCreds instanceof CredentialsImpl) { + if (userId.equals(creds.getUserID()) && userCreds instanceof CredentialsImpl) { success = PasswordUtility.isSame(((CredentialsImpl) userCreds).getPasswordHash(), creds.getPassword()); - } else { - success = false; } checkSuccess(success, "UserId/Password mismatch."); } else if (credentials instanceof ImpersonationCredentials) { - AuthInfo info = ((ImpersonationCredentials) credentials).getImpersonatorInfo(); - success = impersonate(info, user); + ImpersonationCredentials ipCreds = (ImpersonationCredentials) credentials; + AuthInfo info = ipCreds.getImpersonatorInfo(); + success = equalUserId(ipCreds) && impersonate(info, user); checkSuccess(success, "Impersonation not allowed."); } else { // guest login is allowed if an anonymous user exists in the content (see get user above) @@ -116,6 +115,11 @@ class UserAuthentication implements Auth } } + private boolean equalUserId(ImpersonationCredentials creds) { + Credentials base = creds.getBaseCredentials(); + return (base instanceof SimpleCredentials) && userId.equals(((SimpleCredentials) base).getUserID()); + } + private boolean impersonate(AuthInfo info, User user) { try { if (info.getUserID().equals(user.getID())) { Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/AbstractTokenTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/AbstractTokenTest.java?rev=1404313&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/AbstractTokenTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/AbstractTokenTest.java Wed Oct 31 19:28:20 2012 @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.jackrabbit.oak.security.authentication.token; + +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.namepath.NamePathMapper; +import org.apache.jackrabbit.oak.security.AbstractSecurityTest; +import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.junit.After; +import org.junit.Before; + +/** + * AbstractTokenTest... + */ +public abstract class AbstractTokenTest extends AbstractSecurityTest { + + Root root; + TokenProviderImpl tokenProvider; + + String userId; + UserManager userManager; + + @Before + public void before() throws Exception { + super.before(); + + root = admin.getLatestRoot(); + tokenProvider = new TokenProviderImpl(root, + ConfigurationParameters.EMPTY, + getSecurityProvider().getUserConfiguration()); + + userId = "testUser"; + userManager = getSecurityProvider().getUserConfiguration().getUserManager(root, NamePathMapper.DEFAULT); + + userManager.createUser(userId, "pw"); + root.commit(); + } + + @After + public void after() throws Exception { + try { + Authorizable a = userManager.getAuthorizable(userId); + if (a != null) { + a.remove(); + root.commit(); + } + } finally { + super.after(); + } + } +} \ No newline at end of file Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenAuthenticationTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenAuthenticationTest.java?rev=1404313&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenAuthenticationTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenAuthenticationTest.java Wed Oct 31 19:28:20 2012 @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.jackrabbit.oak.security.authentication.token; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import javax.jcr.Credentials; +import javax.jcr.GuestCredentials; +import javax.jcr.SimpleCredentials; +import javax.security.auth.login.LoginException; + +import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; +import org.apache.jackrabbit.oak.spi.security.authentication.Authentication; +import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * TokenAuthenticationTest... + */ +public class TokenAuthenticationTest extends AbstractTokenTest { + + TokenAuthentication authentication; + + @Before + public void before() throws Exception { + super.before(); + authentication = new TokenAuthentication(tokenProvider); + } + @Test + public void testAuthenticateWithoutTokenProvider() throws Exception { + Authentication authentication = new TokenAuthentication(null); + + assertFalse(authentication.authenticate(new TokenCredentials("token"))); + } + + @Test + public void testAuthenticateWithInvalidCredentials() throws Exception { + List<Credentials> invalid = new ArrayList<Credentials>(); + invalid.add(new GuestCredentials()); + invalid.add(new SimpleCredentials(userId, new char[0])); + + for (Credentials creds : invalid) { + assertFalse(authentication.authenticate(creds)); + } + } + + @Test + public void testAuthenticateWithInvalidTokenCredentials() throws Exception { + try { + authentication.authenticate(new TokenCredentials(UUID.randomUUID().toString())); + fail("LoginException expected"); + } catch (LoginException e) { + // success + } + } + + @Test + public void testAuthenticate() throws Exception { + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + assertTrue(authentication.authenticate(new TokenCredentials(info.getToken()))); + } + + @Test + public void testGetTokenInfoBeforeAuthenticate() { + try { + authentication.getTokenInfo(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + // success + } + } + + @Test + public void testGetTokenInfoAfterAuthenticate() throws Exception { + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + authentication.authenticate(new TokenCredentials(info.getToken())); + + TokenInfo info2 = authentication.getTokenInfo(); + assertNotNull(info2); + assertEquals(info.getUserId(), info2.getUserId()); + } +} \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenInfoTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenInfoTest.java?rev=1404313&r1=1404312&r2=1404313&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenInfoTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenInfoTest.java Wed Oct 31 19:28:20 2012 @@ -22,15 +22,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; -import org.apache.jackrabbit.api.security.user.Authorizable; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.apache.jackrabbit.oak.api.Root; -import org.apache.jackrabbit.oak.namepath.NamePathMapper; -import org.apache.jackrabbit.oak.security.AbstractSecurityTest; -import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -41,42 +33,7 @@ import static org.junit.Assert.assertTru /** * TokenInfoTest... */ -public class TokenInfoTest extends AbstractSecurityTest { - - private Root root; - private TokenProviderImpl tokenProvider; - - private String userId; - private UserManager userManager; - - @Before - public void before() throws Exception { - super.before(); - - root = admin.getLatestRoot(); - tokenProvider = new TokenProviderImpl(root, - ConfigurationParameters.EMPTY, - getSecurityProvider().getUserConfiguration()); - - userId = "testUser"; - userManager = getSecurityProvider().getUserConfiguration().getUserManager(root, NamePathMapper.DEFAULT); - - userManager.createUser(userId, "pw"); - root.commit(); - } - - @After - public void after() throws Exception { - try { - Authorizable a = userManager.getAuthorizable(userId); - if (a != null) { - a.remove(); - root.commit(); - } - } finally { - super.after(); - } - } +public class TokenInfoTest extends AbstractTokenTest { @Test public void testGetUserId() { Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java?rev=1404313&r1=1404312&r2=1404313&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java Wed Oct 31 19:28:20 2012 @@ -29,19 +29,11 @@ import javax.jcr.GuestCredentials; import javax.jcr.SimpleCredentials; import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; -import org.apache.jackrabbit.api.security.user.Authorizable; -import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.oak.api.PropertyState; -import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; -import org.apache.jackrabbit.oak.namepath.NamePathMapper; -import org.apache.jackrabbit.oak.security.AbstractSecurityTest; -import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -53,42 +45,7 @@ import static org.junit.Assert.assertTru /** * TokenProviderImplTest... */ -public class TokenProviderImplTest extends AbstractSecurityTest { - - private Root root; - private TokenProviderImpl tokenProvider; - - private String userId; - private UserManager userManager; - - @Before - public void before() throws Exception { - super.before(); - - root = admin.getLatestRoot(); - tokenProvider = new TokenProviderImpl(root, - ConfigurationParameters.EMPTY, - getSecurityProvider().getUserConfiguration()); - - userId = "testUser"; - userManager = getSecurityProvider().getUserConfiguration().getUserManager(root, NamePathMapper.DEFAULT); - - userManager.createUser(userId, "pw"); - root.commit(); - } - - @After - public void after() throws Exception { - try { - Authorizable a = userManager.getAuthorizable(userId); - if (a != null) { - a.remove(); - root.commit(); - } - } finally { - super.after(); - } - } +public class TokenProviderImplTest extends AbstractTokenTest { @Test public void testDoCreateToken() throws Exception { Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthenticationTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthenticationTest.java?rev=1404313&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthenticationTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/UserAuthenticationTest.java Wed Oct 31 19:28:20 2012 @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.jackrabbit.oak.security.authentication.user; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.jcr.Credentials; +import javax.jcr.GuestCredentials; +import javax.jcr.SimpleCredentials; +import javax.security.auth.login.LoginException; + +import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.oak.api.AuthInfo; +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.namepath.NamePathMapper; +import org.apache.jackrabbit.oak.security.AbstractSecurityTest; +import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * UserAuthenticationTest... + */ +public class UserAuthenticationTest extends AbstractSecurityTest { + + private Root root; + + private String userId; + private UserManager userManager; + + private UserAuthentication authentication; + + @Before + public void before() throws Exception { + super.before(); + + root = admin.getLatestRoot(); + + userId = "testUser"; + userManager = getSecurityProvider().getUserConfiguration().getUserManager(root, NamePathMapper.DEFAULT); + + userManager.createUser(userId, "pw"); + root.commit(); + + authentication = new UserAuthentication(userId, userManager); + } + + @After + public void after() throws Exception { + try { + Authorizable a = userManager.getAuthorizable(userId); + if (a != null) { + a.remove(); + root.commit(); + } + } finally { + super.after(); + } + } + + @Test + public void testAuthenticateWithoutUserManager() throws Exception { + UserAuthentication authentication = new UserAuthentication(userId, null); + assertFalse(authentication.authenticate(new SimpleCredentials(userId, "pw".toCharArray()))); + } + + @Test + public void testAuthenticateWithoutUserId() throws Exception { + UserAuthentication authentication = new UserAuthentication(null, userManager); + assertFalse(authentication.authenticate(new SimpleCredentials(userId, "pw".toCharArray()))); + } + + @Test + public void testAuthenticateInvalidCredentials() throws Exception { + List<Credentials> invalid = new ArrayList<Credentials>(); + invalid.add(new TokenCredentials("token")); + invalid.add(new Credentials() {}); + + for (Credentials creds : invalid) { + assertFalse(authentication.authenticate(creds)); + } + } + + @Test + public void testAuthenticateInvalidSimpleCredentials() throws Exception { + List<Credentials> invalid = new ArrayList<Credentials>(); + invalid.add(new SimpleCredentials(userId, "wrongPw".toCharArray())); + invalid.add(new SimpleCredentials(userId, "".toCharArray())); + invalid.add(new SimpleCredentials("unknownUser", "pw".toCharArray())); + + for (Credentials creds : invalid) { + try { + authentication.authenticate(creds); + fail("LoginException expected"); + } catch (LoginException e) { + // success + } + } + } + + @Test + public void testAuthenticateSimpleCredentials() throws Exception { + assertTrue(authentication.authenticate(new SimpleCredentials(userId, "pw".toCharArray()))); + } + + @Test + public void testAuthenticateInvalidImpersonationCredentials() throws Exception { + List<Credentials> invalid = new ArrayList<Credentials>(); + invalid.add(new ImpersonationCredentials(new GuestCredentials(), admin.getAuthInfo())); + invalid.add(new ImpersonationCredentials(new SimpleCredentials(admin.getAuthInfo().getUserID(), new char[0]), new TestAuthInfo())); + invalid.add(new ImpersonationCredentials(new SimpleCredentials("unknown", new char[0]), admin.getAuthInfo())); + invalid.add(new ImpersonationCredentials(new SimpleCredentials("unknown", new char[0]), new TestAuthInfo())); + + for (Credentials creds : invalid) { + try { + authentication.authenticate(creds); + fail("LoginException expected"); + } catch (LoginException e) { + // success + } + } + } + + @Test + public void testAuthenticateImpersonationCredentials() throws Exception { + SimpleCredentials sc = new SimpleCredentials(userId, new char[0]); + assertTrue(authentication.authenticate(new ImpersonationCredentials(sc, admin.getAuthInfo()))); + } + + @Test + public void testAuthenticateImpersonationCredentials2() throws Exception { + SimpleCredentials sc = new SimpleCredentials(userId, new char[0]); + assertTrue(authentication.authenticate(new ImpersonationCredentials(sc, new TestAuthInfo()))); + } + + //-------------------------------------------------------------------------- + + private final class TestAuthInfo implements AuthInfo { + + @Override + public String getUserID() { + return userId; + } + @Nonnull + @Override + public String[] getAttributeNames() { + return new String[0]; + } + @Override + public Object getAttribute(String attributeName) { + return null; + } + @Override + public Set<Principal> getPrincipals() { + return null; + } + } +} \ No newline at end of file