diff --git a/config/alfresco/application-context-highlevel.xml b/config/alfresco/application-context-highlevel.xml index 1b76e0b06e..ab59a407df 100644 --- a/config/alfresco/application-context-highlevel.xml +++ b/config/alfresco/application-context-highlevel.xml @@ -16,6 +16,8 @@ + + diff --git a/config/alfresco/messages/invitation-service_ja.properties b/config/alfresco/messages/invitation-service_ja.properties index d76735cffe..192484219d 100755 --- a/config/alfresco/messages/invitation-service_ja.properties +++ b/config/alfresco/messages/invitation-service_ja.properties @@ -17,7 +17,7 @@ invitation.invitesender.email.subject=Alfresco {0}: \u3042\u306a\u305f\u306f\u30 invitation.invitesender.email.role.SiteManager=\u30b5\u30a4\u30c8\u30de\u30cd\u30fc\u30b8\u30e3 invitation.invitesender.email.role.SiteCollaborator=\u30b5\u30a4\u30c8\u5171\u540c\u4f5c\u696d\u8005 invitation.invitesender.email.role.SiteContributor=\u30b5\u30a4\u30c8\u30b3\u30f3\u30c8\u30ea\u30d3\u30e5\u30fc\u30bf -invitation.invitesender.email.role.SiteConsumer=\u30b5\u30a4\u30c8\u30b2\u30b9\u30c8 +invitation.invitesender.email.role.SiteConsumer=\u30b5\u30a4\u30c8\u5171\u540c\u4f5c\u696d\u8005 # Invitation workflow task description invitation.nominated.workflow.description={0}\u30b5\u30a4\u30c8\u3078\u306e\u53c2\u52a0\u306e\u62db\u5f85 diff --git a/config/alfresco/oauth1-credentials-store-services-context.xml b/config/alfresco/oauth1-credentials-store-services-context.xml new file mode 100644 index 0000000000..ad543c33e9 --- /dev/null +++ b/config/alfresco/oauth1-credentials-store-services-context.xml @@ -0,0 +1,84 @@ + + + + + + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.storePersonalOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.storeSharedOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.getPersonalOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.updateSharedOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.listSharedOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.deletePersonalOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.deleteSharedOAuth1Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.updateCredentialsAuthenticationSucceeded=ACL_ALLOW + org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService.*=ACL_DENY + + + + + + + + + + + getPersonalOAuth1Credentials + listSharedOAuth1Credentials + updateCredentialsAuthenticationSucceeded + + + + + + + + + + + storePersonalOAuth1Credentials + storeSharedOAuth1Credentials + updateSharedOAuth1Credentials + deletePersonalOAuth1Credentials + deleteSharedOAuth1Credentials + + + + + + + + + + + + diff --git a/config/alfresco/oauth2-credentials-store-services-context.xml b/config/alfresco/oauth2-credentials-store-services-context.xml new file mode 100644 index 0000000000..2459667391 --- /dev/null +++ b/config/alfresco/oauth2-credentials-store-services-context.xml @@ -0,0 +1,84 @@ + + + + + + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.storePersonalOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.storeSharedOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.getPersonalOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.updateSharedOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.listSharedOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.deletePersonalOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.deleteSharedOAuth2Credentials=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.updateCredentialsAuthenticationSucceeded=ACL_ALLOW + org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService.*=ACL_DENY + + + + + + + + + + + getPersonalOAuth2Credentials + listSharedOAuth2Credentials + updateCredentialsAuthenticationSucceeded + + + + + + + + + + + storePersonalOAuth2Credentials + storeSharedOAuth2Credentials + updateSharedOAuth2Credentials + deletePersonalOAuth2Credentials + deleteSharedOAuth2Credentials + + + + + + + + + + + + diff --git a/config/alfresco/remote-credentials-services-context.xml b/config/alfresco/remote-credentials-services-context.xml index 91c05886f8..4efbdd42b1 100644 --- a/config/alfresco/remote-credentials-services-context.xml +++ b/config/alfresco/remote-credentials-services-context.xml @@ -64,6 +64,7 @@ + diff --git a/config/alfresco/subsystems/fileServers/default/file-servers-context.xml b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml index 5cdc9bf594..31d120cf9a 100644 --- a/config/alfresco/subsystems/fileServers/default/file-servers-context.xml +++ b/config/alfresco/subsystems/fileServers/default/file-servers-context.xml @@ -489,6 +489,8 @@ + + diff --git a/config/alfresco/subsystems/fileServers/default/file-servers.properties b/config/alfresco/subsystems/fileServers/default/file-servers.properties index 06c8fd1b6f..982c1b9e14 100644 --- a/config/alfresco/subsystems/fileServers/default/file-servers.properties +++ b/config/alfresco/subsystems/fileServers/default/file-servers.properties @@ -4,6 +4,7 @@ filesystem.acl.global.defaultAccessLevel= # AVM filesystem context filesystem.avm.name=AVM +# Are the virtual views enabled filesystem.avm.enabled=true # virtual view stores filter can be any of the following: normal, site, staging, author, preview filesystem.avm.stores=site,staging,author diff --git a/source/java/org/alfresco/filesys/FTPServerTest.java b/source/java/org/alfresco/filesys/FTPServerTest.java index 2d6c29b765..24aed7dc88 100644 --- a/source/java/org/alfresco/filesys/FTPServerTest.java +++ b/source/java/org/alfresco/filesys/FTPServerTest.java @@ -246,8 +246,8 @@ public class FTPServerTest extends TestCase assertTrue(FTPReply.isPositiveCompletion(reply)); // expect /Alfresco directory - // /AVM directory - assertTrue(files.length == 2); + // /AVM directory - avm removed + assertTrue(files.length == 1); boolean foundAVM=false; boolean foundAlfresco=false; @@ -265,7 +265,8 @@ public class FTPServerTest extends TestCase foundAlfresco=true; } } - assertTrue(foundAVM); + // AVM mount point removed + //assertTrue(foundAVM); assertTrue(foundAlfresco); // Change to Alfresco Dir that we know exists diff --git a/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java b/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java index edb558f05d..437fb61bd7 100644 --- a/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java +++ b/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java @@ -242,10 +242,6 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean // Load heart-beat special service (even if disabled at the moment) heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat"); - for(LicenseChangeHandler handler : deferredHandlers) - { - licenseService.registerOnLicenseChange(handler); - } // Now listen for future license changes licenseService.registerOnLicenseChange(this); @@ -677,19 +673,4 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean LicenseMode.UNKNOWN); } } - - - Set deferredHandlers = new HashSet(); - @Override - public void registerOnLicenseChange(LicenseChangeHandler callback) - { - if(licenseService != null) - { - licenseService.registerOnLicenseChange(callback); - } - else - { - deferredHandlers.add(callback); - } - } } diff --git a/source/java/org/alfresco/repo/node/SystemNodeUtils.java b/source/java/org/alfresco/repo/node/SystemNodeUtils.java new file mode 100644 index 0000000000..082946887c --- /dev/null +++ b/source/java/org/alfresco/repo/node/SystemNodeUtils.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.node; + +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.model.Repository; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utilities for working with System Nodes + * + * @author Nick Burch + * @since 4.1 + */ +public abstract class SystemNodeUtils +{ + /** + * The logger + */ + private static Log logger = LogFactory.getLog(SystemNodeUtils.class); + + private static QName SYSTEM_FOLDER_QNAME = + QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); + + /** + * Returns the System Container for the current tenant + */ + public static NodeRef getSystemContainer(final NodeService nodeService, final Repository repositoryHelper) + { + // Grab the root of the repository, for the current tennant + final NodeRef root = repositoryHelper.getRootHome(); + + // Locate the system folder, in the root + List sysRefs = nodeService.getChildAssocs( + root, ContentModel.ASSOC_CHILDREN, SYSTEM_FOLDER_QNAME); + if (sysRefs.size() != 1) + { + throw new IllegalStateException("System folder missing / duplicated! Found " + sysRefs); + } + final NodeRef system = sysRefs.get(0).getChildRef(); + + return system; + } + + /** + * Returns the NodeRef of a given Child Container within the current Tenant's + * System Container, if found + */ + public static NodeRef getSystemChildContainer(final QName childName, final NodeService nodeService, final Repository repositoryHelper) + { + NodeRef system = getSystemContainer(nodeService, repositoryHelper); + + // Find the container, under system + List containerRefs = nodeService.getChildAssocs( + system, ContentModel.ASSOC_CHILDREN, childName); + + NodeRef container = null; + if (containerRefs.size() > 0) + { + container = containerRefs.get(0).getChildRef(); + if (containerRefs.size() > 1) + logger.warn("Duplicate Shared Credentials Containers found: " + containerRefs); + } + + return container; + } + + /** + * Returns the NodeRef of a given Child Container within the current Tenant's System Container, + * creating the Container as System if required. + * The calling code should handle retries, locking etc. + * + * @return the Child Container NodeRef, and whether the Container has just been created + */ + public static Pair getOrCreateSystemChildContainer(final QName childName, + final NodeService nodeService, final Repository repositoryHelper) + { + NodeRef container = getSystemChildContainer(childName, nodeService, repositoryHelper); + if (container != null) + { + return new Pair(container, Boolean.FALSE); + } + + // Create + container = AuthenticationUtil.runAsSystem(new RunAsWork() { + @Override + public NodeRef doWork() throws Exception + { + NodeRef system = getSystemContainer(nodeService, repositoryHelper); + + NodeRef container = nodeService.createNode( + system, ContentModel.ASSOC_CHILDREN, childName, ContentModel.TYPE_CONTAINER + ).getChildRef(); + nodeService.setProperty(container, ContentModel.PROP_NAME, childName.getLocalName()); + + return container; + } + }); + + return new Pair(container, Boolean.TRUE); + } +} diff --git a/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceImpl.java b/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceImpl.java new file mode 100644 index 0000000000..fc0d0327e1 --- /dev/null +++ b/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceImpl.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.oauth1; + +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.query.CannedQueryPageDetails; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.remotecredentials.OAuth1CredentialsInfoImpl; +import org.alfresco.repo.remotecredentials.RemoteCredentialsModel; +import org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService; +import org.alfresco.service.cmr.remotecredentials.OAuth1CredentialsInfo; +import org.alfresco.service.cmr.remotecredentials.RemoteCredentialsService; +import org.alfresco.service.cmr.remoteticket.NoSuchSystemException; + +/** + * @author Jared Ottley + */ +public class OAuth1CredentialsStoreServiceImpl implements OAuth1CredentialsStoreService +{ + private RemoteCredentialsService remoteCredentialsService; + + public void setRemoteCredentialsService(RemoteCredentialsService remoteCredentialsService) + { + this.remoteCredentialsService = remoteCredentialsService; + } + + /** + * Add or Update OAuth1 Credentials for the current user to the OAuth1 + * Credential Store + * + * @param remoteSystemId + * @param token + * @param secret + + * @return OAuth1CredentialsInfo + */ + @Override + public OAuth1CredentialsInfo storePersonalOAuth1Credentials(String remoteSystemId, + String token, String secret) + throws NoSuchSystemException + { + + OAuth1CredentialsInfo credentials = buildPersonalOAuth1CredentialsInfo(remoteSystemId, + token, secret); + + if (credentials.getNodeRef() != null) + { + return (OAuth1CredentialsInfo) remoteCredentialsService.updateCredentials(credentials); + } + else + { + return (OAuth1CredentialsInfo) remoteCredentialsService.createPersonCredentials( + remoteSystemId, credentials); + } + + } + + /** + * Add Shared OAuth1 Credentials to the OAuth1 Credential Store + * + * @param remoteSystemId + * @param token + * @param secret + * @return OAuth1CredentialsInfo + */ + @Override + public OAuth1CredentialsInfo storeSharedOAuth1Credentials(String remoteSystemId, + String token, String secret) + throws NoSuchSystemException + { + OAuth1CredentialsInfo credentials = buildSharedOAuth1CredentialsInfo(remoteSystemId, + token, secret); + + return (OAuth1CredentialsInfo) remoteCredentialsService.createSharedCredentials( + remoteSystemId, credentials); + } + + /** + * @param exisitingCredentials + * @param remoteSystemId + * @param token + * @param secret + * @return OAuth1CredentialsInfo + */ + @Override + public OAuth1CredentialsInfo updateSharedOAuth1Credentials( + OAuth1CredentialsInfo exisitingCredentials, String remoteSystemId, + String token, String secret) + throws NoSuchSystemException + { + List shared = listSharedOAuth1Credentials(remoteSystemId); + + for (OAuth1CredentialsInfo credential : shared) + { + if (credential.getNodeRef().equals(exisitingCredentials.getNodeRef())) + { + OAuth1CredentialsInfoImpl credentials = new OAuth1CredentialsInfoImpl( + exisitingCredentials.getNodeRef(), + exisitingCredentials.getRemoteSystemName(), + exisitingCredentials.getRemoteSystemContainerNodeRef()); + + credentials.setOAuthToken(token); + credentials.setOAuthSecret(secret); + + return (OAuth1CredentialsInfo) remoteCredentialsService + .updateCredentials(credentials); + + } + } + + throw new AlfrescoRuntimeException( + "Cannot update Credentials which haven't been persisted yet!"); + } + + /** + * @param remoteSystemId + * @param token + * @param secret + * @return OAuth1CredentialsInfo + */ + private OAuth1CredentialsInfo buildPersonalOAuth1CredentialsInfo(String remoteSystemId, + String token, String secret) + { + OAuth1CredentialsInfoImpl credentials = new OAuth1CredentialsInfoImpl(); + + OAuth1CredentialsInfoImpl existing = (OAuth1CredentialsInfoImpl) getPersonalOAuth1Credentials(remoteSystemId); + if (existing != null) + { + credentials = existing; + } + + credentials.setOAuthToken(token); + credentials.setOAuthSecret(secret); + + return credentials; + } + + /** + * @param remoteSystemId + * @param token + * @param secret + * @return OAuth1CredentialsInfo + */ + private OAuth1CredentialsInfo buildSharedOAuth1CredentialsInfo(String remoteSystemId, + String token, String secret) + { + OAuth1CredentialsInfoImpl credentials = new OAuth1CredentialsInfoImpl(); + + credentials.setOAuthToken(token); + credentials.setOAuthSecret(secret); + + return credentials; + } + + /** + * Get the current users OAuth1Credentials for the remote systems + * + * @param remoteSystemId + * @return OAuth1CredentialsInfo + */ + @Override + public OAuth1CredentialsInfo getPersonalOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException + { + return (OAuth1CredentialsInfo) remoteCredentialsService + .getPersonCredentials(remoteSystemId); + } + + /** + * @param remoteSystemId + * @return List + */ + @Override + public List listSharedOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException + { + PagingRequest paging = new PagingRequest(CannedQueryPageDetails.DEFAULT_PAGE_SIZE); + @SuppressWarnings("unchecked") + PagingResults pagingResults = (PagingResults) remoteCredentialsService + .listSharedCredentials(remoteSystemId, + RemoteCredentialsModel.TYPE_OAUTH1_CREDENTIALS, paging); + return pagingResults.getPage(); + } + + /** + * Delete the current users OAuth1 Credentials for the remote system + * + * @param remoteSystemId + * @return boolean + */ + @Override + public boolean deletePersonalOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException + { + OAuth1CredentialsInfo credentials = getPersonalOAuth1Credentials(remoteSystemId); + + if (credentials == null) { return false; } + + remoteCredentialsService.deleteCredentials(credentials); + + return true; + } + + @Override + public boolean deleteSharedOAuth1Credentials(String remoteSystemId, + OAuth1CredentialsInfo credentials) throws NoSuchSystemException + { + List shared = listSharedOAuth1Credentials(remoteSystemId); + + if (shared.isEmpty()) { return false; } + + for (OAuth1CredentialsInfo credential : shared) + { + if (credential.getNodeRef().equals(credentials.getNodeRef())) + { + remoteCredentialsService.deleteCredentials(credential); + } + else + { + return false; + } + } + + return true; + } + + /** + * @param succeeded + * @param credentials + * @return + */ + @Override + public OAuth1CredentialsInfo updateCredentialsAuthenticationSucceeded(boolean succeeded, + OAuth1CredentialsInfo credentials) + { + return (OAuth1CredentialsInfo) remoteCredentialsService + .updateCredentialsAuthenticationSucceeded(succeeded, credentials); + } +} diff --git a/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java b/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java new file mode 100644 index 0000000000..4534dbaf4f --- /dev/null +++ b/source/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.oauth1; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService; +import org.alfresco.service.cmr.remotecredentials.OAuth1CredentialsInfo; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.PropertyMap; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.ApplicationContext; + +public class OAuth1CredentialsStoreServiceTest +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private static OAuth1CredentialsStoreService oauth1CredentialsStoreService; + private static ServiceRegistry serviceRegistry; + private static RetryingTransactionHelper transactionHelper; + private static MutableAuthenticationService authenticationService; + private static PersonService personService; + + private static String RemoteSystemId = "Test-OAuth1RemoteSystem"; + + //New + private static String Token = "123456789ABC"; + private static String Secret = "CBA987654321"; + + //Updated + private static String UpdatedToken = "abcdefghi123"; + private static String UpdatedSecret = "321ihgfedcba"; + + //Users + private static String TEST_USER_ONE = OAuth1CredentialsStoreService.class.getSimpleName() + "testuser1"; + private static String TEST_USER_TWO = OAuth1CredentialsStoreService.class.getSimpleName() + "testuser2"; + private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName(); + + @BeforeClass + public static void setUp() throws Exception + { + serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + transactionHelper = serviceRegistry.getRetryingTransactionHelper(); + authenticationService = serviceRegistry.getAuthenticationService(); + personService = serviceRegistry.getPersonService(); + oauth1CredentialsStoreService = (OAuth1CredentialsStoreService) ctx.getBean("oauth1CredentialsStoreService"); + + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + createUser(TEST_USER_ONE); + createUser(TEST_USER_TWO); + } + + @AfterClass + public static void tearDown() throws Exception + { + // Do the teardown as admin + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + deleteUser(TEST_USER_ONE); + deleteUser(TEST_USER_TWO); + } + + @Test + public void testStorePersonalOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Store new credentials + oauth1CredentialsStoreService.storePersonalOAuth1Credentials(RemoteSystemId, Token, Secret); + OAuth1CredentialsInfo oAuth1CredentialsInfo = oauth1CredentialsStoreService.getPersonalOAuth1Credentials(RemoteSystemId); + + assertEquals("Expect that access tokens will match", Token, oAuth1CredentialsInfo.getOAuthToken()); + assertEquals("Expect the refresh token will match", Secret, oAuth1CredentialsInfo.getOAuthSecret()); + + //Update credentials + oauth1CredentialsStoreService.storePersonalOAuth1Credentials(RemoteSystemId, UpdatedToken, UpdatedSecret); + OAuth1CredentialsInfo _oAuth1CredentialsInfo = oauth1CredentialsStoreService.getPersonalOAuth1Credentials(RemoteSystemId); + + assertEquals("Expect that access tokens will match", UpdatedToken, _oAuth1CredentialsInfo.getOAuthToken()); + assertEquals("Expect the refresh token will match", UpdatedSecret, _oAuth1CredentialsInfo.getOAuthSecret()); + } + + @Test + public void testStoreSharedOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Store new credentials + oauth1CredentialsStoreService.storeSharedOAuth1Credentials(RemoteSystemId, Token, Secret); + + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + List sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId); + OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0); + + assertEquals("Expect that access tokens will match", Token, oAuth1CredentialsInfo.getOAuthToken()); + assertEquals("Expect the refresh token will match", Secret, oAuth1CredentialsInfo.getOAuthSecret()); + } + + @Test (expected=AccessDeniedException.class) + public void testSecureUpdateSharedOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + //Update credentials + List sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId); + OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0); + oauth1CredentialsStoreService.updateSharedOAuth1Credentials(oAuth1CredentialsInfo, RemoteSystemId, UpdatedToken, UpdatedSecret); + } + + @Test + public void testUpdateSharedOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Update credentials + List sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId); + OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0); + OAuth1CredentialsInfo _oAuth1CredentialsInfo = oauth1CredentialsStoreService.updateSharedOAuth1Credentials(oAuth1CredentialsInfo, RemoteSystemId, UpdatedToken, UpdatedSecret); + + assertEquals("Expect that access tokens will match", UpdatedToken, _oAuth1CredentialsInfo.getOAuthToken()); + assertEquals("Expect the refresh token will match", UpdatedSecret, _oAuth1CredentialsInfo.getOAuthSecret()); + } + + @Test + public void testDeletePesonalOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + boolean deleted = oauth1CredentialsStoreService.deletePersonalOAuth1Credentials(RemoteSystemId); + + assertTrue(deleted); + + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + boolean _deleted = oauth1CredentialsStoreService.deletePersonalOAuth1Credentials(RemoteSystemId); + + assertFalse(_deleted); + } + + @Test(expected=AccessDeniedException.class) + public void testSecureDeleteSharedOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + List sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId); + OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0); + oauth1CredentialsStoreService.deleteSharedOAuth1Credentials(RemoteSystemId, oAuth1CredentialsInfo); + } + + @Test + public void testDeleteSharedOAuth1Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + List sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId); + OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0); + boolean deleted = oauth1CredentialsStoreService.deleteSharedOAuth1Credentials(RemoteSystemId, oAuth1CredentialsInfo); + + assertTrue(deleted); + } + + + // -------------------------------------------------------------------------------- + + + private static void createUser(final String userName) + { + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (!authenticationService.authenticationExists(userName)) + { + authenticationService.createAuthentication(userName, "PWD".toCharArray()); + } + + if (!personService.personExists(userName)) + { + PropertyMap ppOne = new PropertyMap(); + ppOne.put(ContentModel.PROP_USERNAME, userName); + ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); + ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); + ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); + ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); + + personService.createPerson(ppOne); + } + + return null; + } + }); + } + + private static void deleteUser(final String userName) + { + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (personService.personExists(userName)) + { + personService.deletePerson(userName); + } + + return null; + } + }); + } + +} diff --git a/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceImpl.java b/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceImpl.java new file mode 100644 index 0000000000..76b9046100 --- /dev/null +++ b/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceImpl.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.oauth2; + +import java.util.Date; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.query.CannedQueryPageDetails; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.remotecredentials.OAuth2CredentialsInfoImpl; +import org.alfresco.repo.remotecredentials.RemoteCredentialsModel; +import org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService; +import org.alfresco.service.cmr.remotecredentials.OAuth2CredentialsInfo; +import org.alfresco.service.cmr.remotecredentials.RemoteCredentialsService; +import org.alfresco.service.cmr.remoteticket.NoSuchSystemException; + +/** + * @author Jared Ottley + */ +public class OAuth2CredentialsStoreServiceImpl implements OAuth2CredentialsStoreService +{ + private RemoteCredentialsService remoteCredentialsService; + + public void setRemoteCredentialsService(RemoteCredentialsService remoteCredentialsService) + { + this.remoteCredentialsService = remoteCredentialsService; + } + + /** + * Add or Update OAuth2 Credentials for the current user to the OAuth2 + * Credential Store + * + * @param remoteSystemId + * @param accessToken + * @param refresh Token + * @param expiresAt + * @param issuedAt if null, the current Datetime will be used + * @return OAuth2CredentialsInfo + */ + @Override + public OAuth2CredentialsInfo storePersonalOAuth2Credentials(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException + { + + OAuth2CredentialsInfo credentials = buildPersonalOAuth2CredentialsInfo(remoteSystemId, + accessToken, refreshToken, expiresAt, issuedAt); + + if (credentials.getNodeRef() != null) + { + return (OAuth2CredentialsInfo) remoteCredentialsService.updateCredentials(credentials); + } + else + { + return (OAuth2CredentialsInfo) remoteCredentialsService.createPersonCredentials( + remoteSystemId, credentials); + } + + } + + /** + * Add Shared OAuth2 Credentials to the OAuth2 Credential Store + * + * @param remoteSystemId + * @param accessToken + * @param refreshToken + * @param expiresAt + * @param issuedAt + * @return OAuth2CredentialsInfo + */ + @Override + public OAuth2CredentialsInfo storeSharedOAuth2Credentials(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException + { + OAuth2CredentialsInfo credentials = buildSharedOAuth2CredentialsInfo(remoteSystemId, + accessToken, refreshToken, expiresAt, issuedAt); + + return (OAuth2CredentialsInfo) remoteCredentialsService.createSharedCredentials( + remoteSystemId, credentials); + } + + /** + * @param exisitingCredentials + * @param remoteSystemId + * @param accessToken + * @param refreshToken + * @param expiresAt + * @param issuedAt + * @return OAuth2CredentialsInfo + */ + @Override + public OAuth2CredentialsInfo updateSharedOAuth2Credentials( + OAuth2CredentialsInfo exisitingCredentials, String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException + { + List shared = listSharedOAuth2Credentials(remoteSystemId); + + for (OAuth2CredentialsInfo credential : shared) + { + if (credential.getNodeRef().equals(exisitingCredentials.getNodeRef())) + { + OAuth2CredentialsInfoImpl credentials = new OAuth2CredentialsInfoImpl( + exisitingCredentials.getNodeRef(), + exisitingCredentials.getRemoteSystemName(), + exisitingCredentials.getRemoteSystemContainerNodeRef()); + + credentials.setOauthAccessToken(accessToken); + credentials.setOauthRefreshToken(refreshToken); + credentials.setOauthTokenExpiresAt(expiresAt); + if (issuedAt != null) + { + credentials.setOauthTokenIssuedAt(issuedAt); + } + else + { + credentials.setOauthTokenIssuedAt(new Date()); + } + + return (OAuth2CredentialsInfo) remoteCredentialsService + .updateCredentials(credentials); + + } + } + + throw new AlfrescoRuntimeException( + "Cannot update Credentials which haven't been persisted yet!"); + } + + /** + * @param remoteSystemId + * @param accessToken + * @param refreshToken + * @param expiresAt + * @param issuedAt + * @return OAuth2CredentialsInfo + */ + private OAuth2CredentialsInfo buildPersonalOAuth2CredentialsInfo(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + { + OAuth2CredentialsInfoImpl credentials = new OAuth2CredentialsInfoImpl(); + + OAuth2CredentialsInfoImpl existing = (OAuth2CredentialsInfoImpl) getPersonalOAuth2Credentials(remoteSystemId); + if (existing != null) + { + credentials = existing; + } + + credentials.setOauthAccessToken(accessToken); + credentials.setOauthRefreshToken(refreshToken); + credentials.setOauthTokenExpiresAt(expiresAt); + if (issuedAt != null) + { + credentials.setOauthTokenIssuedAt(issuedAt); + } + else + { + credentials.setOauthTokenIssuedAt(new Date()); + } + + return credentials; + } + + /** + * @param remoteSystemId + * @param accessToken + * @param refreshToken + * @param expiresAt + * @param issuedAt + * @return OAuth2CredentialsInfo + */ + private OAuth2CredentialsInfo buildSharedOAuth2CredentialsInfo(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + { + OAuth2CredentialsInfoImpl credentials = new OAuth2CredentialsInfoImpl(); + + credentials.setOauthAccessToken(accessToken); + credentials.setOauthRefreshToken(refreshToken); + credentials.setOauthTokenExpiresAt(expiresAt); + if (issuedAt != null) + { + credentials.setOauthTokenIssuedAt(issuedAt); + } + else + { + credentials.setOauthTokenIssuedAt(new Date()); + } + + return credentials; + } + + /** + * Get the current users OAuth2Credentials for the remote systems + * + * @param remoteSystemId + * @return OAuth2CredentialsInfo + */ + @Override + public OAuth2CredentialsInfo getPersonalOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException + { + return (OAuth2CredentialsInfo) remoteCredentialsService + .getPersonCredentials(remoteSystemId); + } + + /** + * @param remoteSystemId + * @return List + */ + @Override + public List listSharedOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException + { + PagingRequest paging = new PagingRequest(CannedQueryPageDetails.DEFAULT_PAGE_SIZE); + @SuppressWarnings("unchecked") + PagingResults pagingResults = (PagingResults) remoteCredentialsService + .listSharedCredentials(remoteSystemId, + RemoteCredentialsModel.TYPE_OAUTH2_CREDENTIALS, paging); + return pagingResults.getPage(); + } + + /** + * Delete the current users OAuth2 Credentials for the remote system + * + * @param remoteSystemId + * @return boolean + */ + @Override + public boolean deletePersonalOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException + { + OAuth2CredentialsInfo credentials = getPersonalOAuth2Credentials(remoteSystemId); + + if (credentials == null) { return false; } + + remoteCredentialsService.deleteCredentials(credentials); + + return true; + } + + @Override + public boolean deleteSharedOAuth2Credentials(String remoteSystemId, + OAuth2CredentialsInfo credentials) throws NoSuchSystemException + { + List shared = listSharedOAuth2Credentials(remoteSystemId); + + if (shared.isEmpty()) { return false; } + + for (OAuth2CredentialsInfo credential : shared) + { + if (credential.getNodeRef().equals(credentials.getNodeRef())) + { + remoteCredentialsService.deleteCredentials(credential); + } + else + { + return false; + } + } + + return true; + } + + /** + * @param succeeded + * @param credentials + * @return + */ + @Override + public OAuth2CredentialsInfo updateCredentialsAuthenticationSucceeded(boolean succeeded, + OAuth2CredentialsInfo credentials) + { + return (OAuth2CredentialsInfo) remoteCredentialsService + .updateCredentialsAuthenticationSucceeded(succeeded, credentials); + } +} diff --git a/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceTest.java b/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceTest.java new file mode 100644 index 0000000000..dd36311620 --- /dev/null +++ b/source/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceTest.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Date; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService; +import org.alfresco.service.cmr.remotecredentials.OAuth2CredentialsInfo; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.PropertyMap; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.ApplicationContext; + +public class OAuth2CredentialsStoreServiceTest +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private static OAuth2CredentialsStoreService oauth2CredentialsStoreService; + private static ServiceRegistry serviceRegistry; + private static RetryingTransactionHelper transactionHelper; + private static MutableAuthenticationService authenticationService; + private static PersonService personService; + + private static String RemoteSystemId = "Test-OAuth2RemoteSystem"; + + //New + private static String AccessToken = "123456789ABC"; + private static String RefreshToken = "CBA987654321"; + private static long dec291999 = 946450800L; + private static Date ExpiresAt = new Date(dec291999); + private static Date IssuedAt = new Date(dec291999); + + //Updated + private static String UpdatedAccessToken = "abcdefghi123"; + private static String UpdatedRefreshToken = "321ihgfedcba"; + private static long dec292012 = 1356764400L; + private static Date UpdatedExpiresAt = new Date(dec292012); + private static Date UpdatedIssuedAt = new Date(dec292012); + + //Users + private static String TEST_USER_ONE = OAuth2CredentialsStoreService.class.getSimpleName() + "testuser1"; + private static String TEST_USER_TWO = OAuth2CredentialsStoreService.class.getSimpleName() + "testuser2"; + private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName(); + + @BeforeClass + public static void setUp() throws Exception + { + serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + transactionHelper = serviceRegistry.getRetryingTransactionHelper(); + authenticationService = serviceRegistry.getAuthenticationService(); + personService = serviceRegistry.getPersonService(); + oauth2CredentialsStoreService = (OAuth2CredentialsStoreService) ctx.getBean("oauth2CredentialsStoreService"); + + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + createUser(TEST_USER_ONE); + createUser(TEST_USER_TWO); + } + + @AfterClass + public static void tearDown() throws Exception + { + // Do the teardown as admin + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + deleteUser(TEST_USER_ONE); + deleteUser(TEST_USER_TWO); + } + + @Test + public void testStorePersonalOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Store new credentials + oauth2CredentialsStoreService.storePersonalOAuth2Credentials(RemoteSystemId, AccessToken, RefreshToken, ExpiresAt, IssuedAt); + OAuth2CredentialsInfo oAuth2CredentialsInfo = oauth2CredentialsStoreService.getPersonalOAuth2Credentials(RemoteSystemId); + + assertEquals("Expect that access tokens will match", AccessToken, oAuth2CredentialsInfo.getOAuthAccessToken()); + assertEquals("Expect the refresh token will match", RefreshToken, oAuth2CredentialsInfo.getOAuthRefreshToken()); + assertEquals("Expect that the expiration date will match", ExpiresAt, oAuth2CredentialsInfo.getOAuthTicketExpiresAt()); + assertEquals("Expect that the issued date will match", IssuedAt, oAuth2CredentialsInfo.getOAuthTicketIssuedAt()); + + //Update credentials + oauth2CredentialsStoreService.storePersonalOAuth2Credentials(RemoteSystemId, UpdatedAccessToken, UpdatedRefreshToken, UpdatedExpiresAt, UpdatedIssuedAt); + OAuth2CredentialsInfo _oAuth2CredentialsInfo = oauth2CredentialsStoreService.getPersonalOAuth2Credentials(RemoteSystemId); + + assertEquals("Expect that access tokens will match", UpdatedAccessToken, _oAuth2CredentialsInfo.getOAuthAccessToken()); + assertEquals("Expect the refresh token will match", UpdatedRefreshToken, _oAuth2CredentialsInfo.getOAuthRefreshToken()); + assertEquals("Expect that the expiration date will match", UpdatedExpiresAt, _oAuth2CredentialsInfo.getOAuthTicketExpiresAt()); + assertEquals("Expect that the issued date will match", UpdatedIssuedAt, _oAuth2CredentialsInfo.getOAuthTicketIssuedAt()); + } + + @Test + public void testStoreSharedOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Store new credentials + oauth2CredentialsStoreService.storeSharedOAuth2Credentials(RemoteSystemId, AccessToken, RefreshToken, ExpiresAt, IssuedAt); + + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + List sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); + OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0); + + assertEquals("Expect that access tokens will match", AccessToken, oAuth2CredentialsInfo.getOAuthAccessToken()); + assertEquals("Expect the refresh token will match", RefreshToken, oAuth2CredentialsInfo.getOAuthRefreshToken()); + assertEquals("Expect that the expiration date will match", ExpiresAt, oAuth2CredentialsInfo.getOAuthTicketExpiresAt()); + assertEquals("Expect that the issued date will match", IssuedAt, oAuth2CredentialsInfo.getOAuthTicketIssuedAt()); + } + + @Test (expected=AccessDeniedException.class) + public void testSecureUpdateSharedOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + //Update credentials + List sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); + OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0); + oauth2CredentialsStoreService.updateSharedOAuth2Credentials(oAuth2CredentialsInfo, RemoteSystemId, UpdatedAccessToken, UpdatedRefreshToken, UpdatedExpiresAt, UpdatedIssuedAt); + } + + @Test + public void testUpdateSharedOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + //Update credentials + List sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); + OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0); + OAuth2CredentialsInfo _oAuth2CredentialsInfo = oauth2CredentialsStoreService.updateSharedOAuth2Credentials(oAuth2CredentialsInfo, RemoteSystemId, UpdatedAccessToken, UpdatedRefreshToken, UpdatedExpiresAt, UpdatedIssuedAt); + + assertEquals("Expect that access tokens will match", UpdatedAccessToken, _oAuth2CredentialsInfo.getOAuthAccessToken()); + assertEquals("Expect the refresh token will match", UpdatedRefreshToken, _oAuth2CredentialsInfo.getOAuthRefreshToken()); + assertEquals("Expect that the expiration date will match", UpdatedExpiresAt, _oAuth2CredentialsInfo.getOAuthTicketExpiresAt()); + assertEquals("Expect that the issued date will match", UpdatedIssuedAt, _oAuth2CredentialsInfo.getOAuthTicketIssuedAt()); + } + + @Test + public void testDeletePesonalOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + boolean deleted = oauth2CredentialsStoreService.deletePersonalOAuth2Credentials(RemoteSystemId); + + assertTrue(deleted); + + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + boolean _deleted = oauth2CredentialsStoreService.deletePersonalOAuth2Credentials(RemoteSystemId); + + assertFalse(_deleted); + } + + @Test(expected=AccessDeniedException.class) + public void testSecureDeleteSharedOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_TWO); + List sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); + OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0); + oauth2CredentialsStoreService.deleteSharedOAuth2Credentials(RemoteSystemId, oAuth2CredentialsInfo); + } + + @Test + public void testDeleteSharedOAuth2Credentials() + { + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); + List sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); + OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0); + boolean deleted = oauth2CredentialsStoreService.deleteSharedOAuth2Credentials(RemoteSystemId, oAuth2CredentialsInfo); + + assertTrue(deleted); + } + + + // -------------------------------------------------------------------------------- + + + private static void createUser(final String userName) + { + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (!authenticationService.authenticationExists(userName)) + { + authenticationService.createAuthentication(userName, "PWD".toCharArray()); + } + + if (!personService.personExists(userName)) + { + PropertyMap ppOne = new PropertyMap(); + ppOne.put(ContentModel.PROP_USERNAME, userName); + ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); + ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); + ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); + ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); + + personService.createPerson(ppOne); + } + + return null; + } + }); + } + + private static void deleteUser(final String userName) + { + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (personService.personExists(userName)) + { + personService.deletePerson(userName); + } + + return null; + } + }); + } + +} diff --git a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java index 0a3e1b8d5a..659897883f 100644 --- a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java +++ b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServiceImpl.java @@ -27,12 +27,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.alfresco.model.ContentModel; import org.alfresco.query.EmptyPagingResults; import org.alfresco.query.ListBackedPagingResults; import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingResults; import org.alfresco.repo.model.Repository; +import org.alfresco.repo.node.SystemNodeUtils; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -42,6 +42,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.TypeConversionException; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; @@ -73,6 +74,7 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService private Repository repositoryHelper; private NodeService nodeService; private NamespaceService namespaceService; + private PermissionService permissionService; private DictionaryService dictionaryService; /** @@ -93,6 +95,11 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService this.namespaceService = namespaceService; } + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + public void setDictionaryService(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; @@ -154,8 +161,6 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService // -------------------------------------------------------- - private static QName SYSTEM_FOLDER_QNAME = - QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); private static QName SHARED_CREDENTIALS_CONTAINER_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, SHARED_CREDENTIALS_CONTAINER_NAME); /** @@ -167,43 +172,60 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService */ protected NodeRef getSharedContainerNodeRef(boolean required) { - // Grab the root of the repository, for the current tennant - final NodeRef root = repositoryHelper.getRootHome(); + // Get the container, if available + NodeRef container = SystemNodeUtils.getSystemChildContainer(SHARED_CREDENTIALS_CONTAINER_QNAME, nodeService, repositoryHelper); - // Locate the system folder, in the root - List sysRefs = nodeService.getChildAssocs( - root, ContentModel.ASSOC_CHILDREN, SYSTEM_FOLDER_QNAME); - if (sysRefs.size() != 1) + // If it's needed, have it created + if (container == null && required) { - throw new IllegalStateException("System folder missing / duplicated! Found " + sysRefs); - } - final NodeRef system = sysRefs.get(0).getChildRef(); - - // Find the shared credentials container, under system - List containerRefs = nodeService.getChildAssocs( - system, ContentModel.ASSOC_CHILDREN, SHARED_CREDENTIALS_CONTAINER_QNAME); - - if (containerRefs.size() > 0) - { - if (containerRefs.size() > 1) - logger.warn("Duplicate Shared Credentials Containers found: " + containerRefs); + // Lock and create + Pair details = null; + synchronized (this) + { + details = SystemNodeUtils.getOrCreateSystemChildContainer(SHARED_CREDENTIALS_CONTAINER_QNAME, nodeService, repositoryHelper); + } + container = details.getFirst(); - NodeRef container = containerRefs.get(0).getChildRef(); - return container; + // If created, set permissions + // Note - these must be kept in sync with the bootstrap file + if (details.getSecond()) + { + final NodeRef containerF = container; + AuthenticationUtil.runAsSystem(new RunAsWork() { + @Override + public Void doWork() throws Exception + { + // Add the aspect + nodeService.addAspect(containerF, RemoteCredentialsModel.ASPECT_REMOTE_CREDENTIALS_SYSTEM_CONTAINER, null); + + // Set up the default permissions on the container + // By default, anyone can add children, and read, but not edit other's credentials + // (These can be changed later if needed by an administrator) + permissionService.setInheritParentPermissions(containerF, false); + permissionService.setPermission( + containerF, PermissionService.ALL_AUTHORITIES, + PermissionService.ADD_CHILDREN, true); + permissionService.setPermission( + containerF, PermissionService.ALL_AUTHORITIES, + PermissionService.READ, true); + + permissionService.setPermission( + containerF, PermissionService.OWNER_AUTHORITY, + PermissionService.FULL_CONTROL, true); + + return null; + } + }); + } } - else + + if (container == null) { - if (required) - { - throw new IllegalStateException("Required System Folder " + SHARED_CREDENTIALS_CONTAINER_QNAME + " is missing!"); - } - else - { - if (logger.isInfoEnabled()) - logger.info("Required System Folder " + SHARED_CREDENTIALS_CONTAINER_QNAME + " missing, needed for writes"); - return null; - } + if (logger.isInfoEnabled()) + logger.info("Required System Folder " + SHARED_CREDENTIALS_CONTAINER_QNAME + " not yet created, will be lazy created on write"); + return null; } + return container; } /** diff --git a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java index 0f04f65606..800185e796 100644 --- a/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java +++ b/source/java/org/alfresco/repo/remotecredentials/RemoteCredentialsServicesTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.Set; @@ -43,7 +44,6 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.PropertyMap; @@ -51,6 +51,7 @@ import org.alfresco.util.test.junitrules.ApplicationContextInit; import org.alfresco.util.test.junitrules.TemporaryNodes; import org.alfresco.util.test.junitrules.WellKnownNodes; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -130,16 +131,6 @@ public class RemoteCredentialsServicesTest // Switch to a test shared system container RemoteCredentialsServiceImpl.setSharedCredentialsSystemContainerName(SHARED_SYSTEM_CONTAINER_NAME); - - // Have the test shared system container created - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.SYSTEM_USER_NAME); - NodeRef system = knownNodes.getSystemRoot(); - NodeRef container = PUBLIC_NODE_SERVICE.createNode(system, ContentModel.ASSOC_CHILDREN, - RemoteCredentialsServiceImpl.getSharedCredentialsSystemContainerQName(), - ContentModel.TYPE_CONTAINER - ).getChildRef(); - PERMISSION_SERVICE.setPermission(container, PermissionService.ALL_AUTHORITIES, PermissionService.FULL_CONTROL, true); - classTestNodes.addNodeRef(container); } @Before public void setupUsers() throws Exception @@ -154,7 +145,6 @@ public class RemoteCredentialsServicesTest AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); } - /** * Tests that read only methods don't create the shared credentials * container, but that write ones will do. @@ -165,18 +155,16 @@ public class RemoteCredentialsServicesTest AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); - // To start with, the container is there, but empty + // To start with, the container shouldn't be there NodeRef container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false); - assertNotNull(container); - assertEquals(0, PUBLIC_NODE_SERVICE.getChildAssocs(container).size()); + assertEquals(null, container); // Ask for the list of shared remote systems REMOTE_CREDENTIALS_SERVICE.listSharedRemoteSystems(new PagingRequest(10)); - // Won't have been affected by a read + // Won't have been created by a read container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false); - assertNotNull(container); - assertEquals(0, PUBLIC_NODE_SERVICE.getChildAssocs(container).size()); + assertEquals(null, container); // Try to store some credentials @@ -187,10 +175,11 @@ public class RemoteCredentialsServicesTest container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false); assertNotNull(container); - // Should have a marker aspect + // Should have a marker aspect, and the specified name Set cAspects = PUBLIC_NODE_SERVICE.getAspects(container); assertEquals("Aspect missing, found " + cAspects, true, cAspects.contains(RemoteCredentialsModel.ASPECT_REMOTE_CREDENTIALS_SYSTEM_CONTAINER)); + assertEquals(SHARED_SYSTEM_CONTAINER_NAME, PUBLIC_NODE_SERVICE.getProperty(container, ContentModel.PROP_NAME)); // Should have single node in it assertEquals(1, PUBLIC_NODE_SERVICE.getChildAssocs(container).size()); @@ -905,6 +894,16 @@ public class RemoteCredentialsServicesTest deleteUser(TEST_USER_THREE); } + @AfterClass public static void remoteTestSharedCredentialsContainer() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + NodeRef container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false); + if (container != null) + { + performDeletionOfNodes(Collections.singletonList(container)); + } + } + /** * Deletes the specified NodeRefs, if they exist. * @param nodesToDelete @@ -976,4 +975,4 @@ public class RemoteCredentialsServicesTest } }); } -} \ No newline at end of file +} diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java index 39bb1ae86f..af5245ea9c 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java @@ -26,6 +26,7 @@ import java.util.List; import org.alfresco.model.ContentModel; import org.alfresco.repo.i18n.MessageService; import org.alfresco.repo.importer.ImporterBootstrap; +import org.alfresco.repo.node.SystemNodeUtils; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -235,6 +236,8 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent /** * Gets the system workflow container for storing workflow related items * + * TODO Replace this with calls to {@link SystemNodeUtils} + * * @return the system workflow container */ private NodeRef getSystemWorkflowContainer() diff --git a/source/java/org/alfresco/service/cmr/oauth1/OAuth1CredentialsStoreService.java b/source/java/org/alfresco/service/cmr/oauth1/OAuth1CredentialsStoreService.java new file mode 100644 index 0000000000..97e209a379 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/oauth1/OAuth1CredentialsStoreService.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.oauth1; + +import java.util.List; + +import org.alfresco.service.Auditable; +import org.alfresco.service.cmr.remotecredentials.OAuth1CredentialsInfo; +import org.alfresco.service.cmr.remoteticket.NoSuchSystemException; + +/** + * + * @author Jared Ottley + */ +public interface OAuth1CredentialsStoreService +{ + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth1CredentialsInfo storePersonalOAuth1Credentials(String remoteSystemId, + String token, String secret) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth1CredentialsInfo storeSharedOAuth1Credentials(String remoteSystemId, + String token, String secret) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth1CredentialsInfo getPersonalOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth1CredentialsInfo updateSharedOAuth1Credentials( + OAuth1CredentialsInfo exisitingCredentials, String remoteSystemId, + String token, String secret) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract List listSharedOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract boolean deletePersonalOAuth1Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract boolean deleteSharedOAuth1Credentials(String remoteSystemId, + OAuth1CredentialsInfo credentials) throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth1CredentialsInfo updateCredentialsAuthenticationSucceeded( + boolean succeeded, OAuth1CredentialsInfo credentials); + +} \ No newline at end of file diff --git a/source/java/org/alfresco/service/cmr/oauth2/OAuth2CredentialsStoreService.java b/source/java/org/alfresco/service/cmr/oauth2/OAuth2CredentialsStoreService.java new file mode 100644 index 0000000000..5b9e7258c7 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/oauth2/OAuth2CredentialsStoreService.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.oauth2; + +import java.util.Date; +import java.util.List; + +import org.alfresco.service.Auditable; +import org.alfresco.service.cmr.remotecredentials.OAuth2CredentialsInfo; +import org.alfresco.service.cmr.remoteticket.NoSuchSystemException; + +/** + * + * @author Jared Ottley + */ +public interface OAuth2CredentialsStoreService +{ + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth2CredentialsInfo storePersonalOAuth2Credentials(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth2CredentialsInfo storeSharedOAuth2Credentials(String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth2CredentialsInfo getPersonalOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth2CredentialsInfo updateSharedOAuth2Credentials( + OAuth2CredentialsInfo exisitingCredentials, String remoteSystemId, + String accessToken, String refreshToken, Date expiresAt, Date issuedAt) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract List listSharedOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract boolean deletePersonalOAuth2Credentials(String remoteSystemId) + throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract boolean deleteSharedOAuth2Credentials(String remoteSystemId, + OAuth2CredentialsInfo credentials) throws NoSuchSystemException; + + @Auditable(parameters = { "remoteSystemId" }) + public abstract OAuth2CredentialsInfo updateCredentialsAuthenticationSucceeded( + boolean succeeded, OAuth2CredentialsInfo credentials); + +} \ No newline at end of file diff --git a/source/java/org/alfresco/service/descriptor/DescriptorService.java b/source/java/org/alfresco/service/descriptor/DescriptorService.java index c369a6e166..45a39091fa 100644 --- a/source/java/org/alfresco/service/descriptor/DescriptorService.java +++ b/source/java/org/alfresco/service/descriptor/DescriptorService.java @@ -114,10 +114,5 @@ public interface DescriptorService * @return Returns a message telling the user what happened */ public String loadLicense(); - - /** - * Register a callback that gets called when a license changes. - */ - public void registerOnLicenseChange(LicenseChangeHandler callback); - + }