Merged V4.1-BUG-FIX to HEAD

40164: Merged V4.0.2 to V4.1-BUG-FIX (4.1.1)
      - Partial merge of r39519 on V4.1 which included something from V4.1-BUG-FIX
      39494: ALF-15170: Can't change folder permissions in Private or Public-moderated sites
      - Fix by Dmitry V
      38899: ALF-15005: Merged V4.0-BUG-FIX to PATCHES/V4.0.2
         37920: ALF-13816: Permission Denied on web-client browsing if parent does not inherit permissions
            - FileFolderService getNamePath() now performs toFileInfo() as SystemUser.
   40167: Merged V4.1 (4.1.0) to V4.1-BUG-FIX (4.1.1)
      40156: Adds defensive code to avoid situations where the parent can't be found (e.g. RM-474)
      40144: ALF-11027: update URLs to deploy to our internal-snapshot Maven repo, so that GoogleDocs integration can take advantage of it
      40121: Chinese: Translation update based on EN r40086
      40120: Dutch: Translation update based on EN r40086
      40119: Japanese: Translation update based on EN r40086
      40118: Italian: Translation update based on EN r40086
      40117: French: Translation update based on EN r40086
      40116: Spanish: Translation update based on EN r40086
      40115: German: Translation update based on EN r40086
      40103: Unit test fix following removal of AVM file context.
      40076: Fixes encoding error introduced in r40072.
      40072: Error message string updates, based on feedback from Docs.
      40069: ALF-15364	CloudSync: folder sync with lock on-premise - pulled new file is not auto-locked
      40068: Java doc corrections.
      40067: CloudSync: ALF-15287 - folder sync to a clashing name hierarchy causes file to be indirectly synced to the wrong place
      - was "An unsynced file which was synced indirectly will be synced in the documentLibrary"
      - plus unit test
      40065: Removal of potential NullPointerException (not observed).
      40063: Chinese: Translation updates from Gloria, based on EN r40019
      40062: Dutch: Translation updates from Gloria, based on EN r40019
      40061: Italian: Translation updates from Gloria, based on EN r40019
      40060: French: Translation updates from Gloria, based on EN r40019
      40059: Japanese: Translation updates from Gloria, based on EN r40019
      40058: Spanish: Translation updates from Gloria, based on EN r40019
      40057: German: Translation updates from Gloria, based on EN r40019
      40054: CloudSync: add simple *folder* sync unit test !
      40053: ALF-15218 - AVM must not be visible by default in VFS mount points
      40036: Addressing the important question raised in ALF-14950.
      I have decided that, as pointed out by MikeF, a sensible solution for handling secondary child-assocs that link nodes to synced folders would be to NOT sync those nodes.
      So I've made it such that new nodes are only added into a syncset if they are created as *primary* children of a synced folder. If they are secondary children, they are not added as members.
      Test case for same.
      40019: Having fixed the TemporaryNodes @Rule in rev 40010 so that it handles checked-out test files gracefully, I'm removing Jan's workaround for a checked-out test file.
      40017: During work for ALF-15296, I've fixed up the error handling during sync set creation.
      See ts doc: https://ts.alfresco.com/share/page/site/projectodin/document-details?nodeRef=workspace://SpacesStore/47bf11a3-8d30-4377-a373-1c1d3fba6018
      Now Sync Set creation can fail if there are some problems with the provided direct member nodes.
      If there are problems with any indirect members, that will not cause the sync to fail during setup, but subsequent pushes to the Cloud will fail with appropriate error reporting.
      Exceptions during the creation of a syncset can now report multiple failed nodes.
      Rewrote the cannotCreateTwoSyncSetDefinitionsWithOverlappingLocalMembers() testcase to be creatingTwoSyncSetDefinitionsWithOverlappingLocalMembersShouldSilentlyDropTheOverlaps()
      Extra test cases for sync setup:
      syncing a list of ineligible nodes should throw an exception.
      Syncing a list of nodes, some of which are ineligible, should skip the ineligable ones.
      Syncing a folder containing already-synced child nodes and unwriteable child nodes should silently
      skip the already-synced, but include the unwriteable nodes as members (which will fail to sync).
      Various tidy-ups and comments to explain this behaviour to the next coder, which may be me. :)
      40014: ALF-15218 - AVM must not be visible by default in VFS mount points
      40010: Enhancement to TemporaryNodes JUnit @Rule so that it gracefully handles checked-out nodes during test code.
      39996: ALF-14377: Need to decide what to do when SSD creator user is no longer valid
      39986: Chinese: Translation updates from Gloria, based on EN r39671
      39985: Dutch: Translation updates from Gloria, based on EN r39671
      39984: Japanese: Translation updates from Gloria, based on EN r39671
      39983: Italian: Translation updates from Gloria, based on EN r39671
      39982: French: Translation updates from Gloria, based on EN r39671
      39981: Spanish: Translation updates from Gloria, based on EN r39671
      39980: German: Translation updates from Gloria, based on EN r39671
      39957: CloudSync: minor - some info logging (applies to src + tgt)
      39943: CloudSync: fix remainder of ALF-15130 - sync time for initial sync of working copy (+ unit test)
      39942: ALF-14911 - Path shown in the version comments does not match the path shown in the sync status dialogue
         - first part share paths are now handled separatly
      39933: ALF-14179: Merged PATCHES/V4.0.2 to V4.1
         39929: ALF-15330: Merged V3.4-BUG-FIX to PATCHES/V4.0.2
            39681: Fix CIFS hang on file open of MS Office document. ALF-13578, ALF-15092.
               Async packet queue not being cleared at end of request processing.
      39924: CSS fixes for the sync panel
      39918: Merged DEV to V4.1
         39911: ALF-15263 : XAM: XAM Connector cannot be installed on Alfresco v4.1
      39915: ALF-14908: Update Sync status dialogue to include the local root folder for indirectly synced nodes
      39904: ALF-15041: Cloud Sync doesn't work with IE7
      39903: ALF-15041: Cloud Sync doesn't work with IE7
      39902: ALF-15041: Cloud Sync doesn't work with IE7
      39883: CloudSync: fix ALF-15270 - moving directly synced node (on source) causes target node to be deleted
      - ... add related move file sync unit test
      39876: ALF-15301: IE8 specific: It is impossible creating a new folder in a cloud target selection window/Cloud location
      39864: ALF-15003 Sync failed for the file (where write access on source removed for sync owner) but no matter this file appears in Cloud
      39863: ALF-15268: Cancel button disabled in the target selection window for new folder creation in Cloud
      39860: ALF-14908: Update Sync status dialogue to include the local root folder for indirectly synced nodes.
      39859: ALF-15249 Add a new method hasSyncSetDefintions, with unit test, and use this to skip the Sync Pull step on-premise if no SSDs have been defined on the local system
      39847: ALF-15185: YUI Overlay Mozilla Scrollbar fix should be prevented in recent versions of Firefox too.
      39826: ALF-14377 - Need to decide what to do when SSD creator user is no longer valid
      Implementation of "last gasp" unsync for the case where the sync set owner does not exist.
      39820: ALF-15267: Edit online is available for locked on-premise copy 
      and can unlock it
      ALF-15284: The actions "Upload New Version" and "Inline Edit" should not be available for a "synced" and "locked" node
      39812: UI Bug Fixes:
         - ALF-15174: Uses already copied slingshot.properties file for message strings needed in both repo and Share
         - Cloud delete file message shouldn't refer to the cloud
      39810: ALF-15221: Cloud Sync Status: Failure message when getting location is misleading
      39767: CloudSync: fix ALF-15145 - Unsync of a folder (sync) that has a working copy file causes indirect icon to remain ...
      ... on working copy (until checkin or cancel checkout)
      39748: CloudSync: fix compile error
      - failed manual "merge" (oops, sorry)
      39747: ALF-14377	Need to decide what to do when SSD creator user is no longer valid 
         - part 1 nodes are marked.
      39735: CloudSync: ALF-14483 - multi-threaded SyncTracker
      - fix related to unit test failure (affecting CLOUD1 but not V4.1)
      - also add default (info) Sync log level
      39729: Merged PATCHES/V4.0.2 to V4.1
         39725: ALF-15176: Multi-threaded SOLR tracking suddenly stops leaving transactions unindexed
            - Debugged on environment provided by Antonio
            - If the last incomplete batch in a chunk consists entirely of empty transactions (or transactions consisting entirely of nodes updated in later transactions) it would loop forever
      39687: Enterprise license for enterprise remote api project
      39686: Replaced GPL license with enterprise licence.
      39683: ALF-15162 - Unclear error message when delta syncing and the target is gone
      39677: ALF-14903 Move the Sync allowed/not-allowed check, based on Network/Tenant, to AbstractCloudSyncAbstractWebScript, and have this used by the webscripts based on this too. Then, allow UnSync to proceed no matter what the tenant status, and add unit tests
      39673: New unit test for adding checked out nodes into a sync set.
      39670: Rework to cloud key license stuff - introduces a ValidLicenseEvent
      39664: CloudSync: ALF-14483 - SyncTracker unit tests - simple file sync test
      - initially run with single-threaded push/pull (will require further investigation on cloud branch)
      39653: ALF-15041: Cloud Sync doesn't work with IE7
      39643: ALF-15220: Indirect sync and sync failed indicators appeared together on nodes during the demo
      39641: ALF-15230 Refactor the lazy container creation code, to use the new SystemNodeUtils helper
      39640: ALF-15231 Restore, with refactorings / making more general, the ability to lazy create the remote credentials container if bootstrap has not created it (eg on Cloud)
      39639: ALF-15238: Bitrock Installer: Readme.txt should be updated - Alfresco version is 4.0
      39633: CloudSync: ALF-14483 - SyncTracker - enable sync sets to be processed in parallel
      - wip default of 6 threads (3 to push / 3 to pull)
      39616: CloudSync: CloudSync: ALF-14483 - SyncTracker - multiple syncs (to different tgt folders) with multiple files
      - make sure the multi-threaded tracker is excercised via automated unit tests
      39613: Refactor of test code. SyncTrackerComponentTest now uses JUnit Rules to manage temporary content and to undo mocking out of services.
      39607: CloudSync: ALF-14483 - SyncTracker - enable sync sets to be pushed in parallel
      - wip / default 3 threads
      39606: CloudSync: minor log level adjustments
      - eg. info vs debug (vs trace)
      39598: CloudSync: ALF-14655 - update simple file sync (to test multiple sync'd files)
      39597: CloudSync: tweak a couple of unit tests
      - add "run id" to allow them to be locally re-runnable (in case of error)
      39589: ALF-15098: Folder Picker causes JS error in the document details page
      39587: ALF-15222: Cloud Folder picker: Newly created folder isn't selected
      39580: CloudSync: fix Unsync - to ensure we don't leave sync aspects (such as failed, which reappears if src file is re-synced)
      - found by MF ... thanks
      - unit test added
      39574: Cloud lacks a guest mode, so switch to unauthenticated for the sync mode fetch (user credentials may not be available)
      39566: Allow the sync mode to be fetched by guest (it need not be hidden), then fetch from Share as guest, to avoid problems when fetching the sync mode if the current user's credentials have expired (otherwise it breaks the redirect back to the login)
      39561: Merged THOR1 to V4.1 (try to say that in a hurry!)
         39553: ALF-15149: Prevent an infinite loop in AlfrescoSolrEventListener.RemoveNullEntriesCacheMatch.updateCache()
      39550: Synced folder shouldn't be filtered in the cloud folder picker. The user should be able to see them but not select them (the synced folder should be greyed out)
      39548: CloudSync: ALF-14655 - add SyncTracker unit test for simple file sync
      - initial re-work of SyncTrackerComponentTest ... to make it easier to add more tests (and re-use test fragments)
      - add simple unit test for "file sync" (F4) => sync, push, pull, unsync ...
      - ... also fix potential SyncService unsync issue on target (found by new test)
      39547: Bug fixes (spotted during demo):
       - Remove the "synced with errors" filter from dashlets and doclibrary for the cloud version
       - Remove the last '>' symbol in the info dialogue (path for "Cloud in the Location")
      39546: Merged integrations/GoogleDocs/BRANCHES/OAUTH_V4.1 to BRANCHES/V4.1:
         39504: [ALF-14926][GOOGLEDOCS-23] Merge OAuth2 Credentials Store Service
         39516: Add missing license to OAuth2 Credentials Classes
         39517: oAuth1 Credentials Store Service
      39540: Some fixes to issues identified by findbugs.
      39532: Revert cloud welcome dashlet text.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@40273 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-08-10 08:19:54 +00:00
parent 27f6cb89b8
commit f059a12979
20 changed files with 1562 additions and 83 deletions

View File

@@ -16,6 +16,8 @@
<import resource="classpath:alfresco/links-services-context.xml"/> <import resource="classpath:alfresco/links-services-context.xml"/>
<import resource="classpath:alfresco/rating-services-context.xml"/> <import resource="classpath:alfresco/rating-services-context.xml"/>
<import resource="classpath:alfresco/remote-credentials-services-context.xml"/> <import resource="classpath:alfresco/remote-credentials-services-context.xml"/>
<import resource="classpath:alfresco/oauth1-credentials-store-services-context.xml"/>
<import resource="classpath:alfresco/oauth2-credentials-store-services-context.xml"/>
<import resource="classpath:alfresco/remote-ticket-services-context.xml"/> <import resource="classpath:alfresco/remote-ticket-services-context.xml"/>
<import resource="classpath:alfresco/rendition-services-context.xml"/> <import resource="classpath:alfresco/rendition-services-context.xml"/>
<import resource="classpath:alfresco/replication-services-context.xml"/> <import resource="classpath:alfresco/replication-services-context.xml"/>

View File

@@ -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.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.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.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 workflow task description
invitation.nominated.workflow.description={0}\u30b5\u30a4\u30c8\u3078\u306e\u53c2\u52a0\u306e\u62db\u5f85 invitation.nominated.workflow.description={0}\u30b5\u30a4\u30c8\u3078\u306e\u53c2\u52a0\u306e\u62db\u5f85

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="OAuth1CredentialsStoreService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.service.cmr.oauth1.OAuth1CredentialsStoreService</value>
</property>
<property name="target">
<ref bean="oauth1CredentialsStoreService"/>
</property>
<property name="interceptorNames">
<list>
<idref bean="oauth1CredentialsStoreServiceReadTxnAdvisor"/>
<idref bean="oauth1CredentialsStoreServiceWriteTxnAdvisor"/>
<idref bean="AuditMethodInterceptor"/>
<idref bean="exceptionTranslator"/>
<idref bean="oauth1SCredentialsStoreService_security"/>
</list>
</property>
</bean>
<bean id="oauth1SCredentialsStoreService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="afterInvocationManager">
<ref bean="afterInvocationManager"/>
</property>
<property name="objectDefinitionSource">
<value>
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
</value>
</property>
</bean>
<bean id="oauth1CredentialsStoreServiceReadTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref bean="retryingReadTxnAdvice"/>
</property>
<property name="mappedNames">
<list>
<value>getPersonalOAuth1Credentials</value>
<value>listSharedOAuth1Credentials</value>
<value>updateCredentialsAuthenticationSucceeded</value>
</list>
</property>
</bean>
<bean id="oauth1CredentialsStoreServiceWriteTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref bean="retryingWriteTxnAdvice"/>
</property>
<property name="mappedNames">
<list>
<value>storePersonalOAuth1Credentials</value>
<value>storeSharedOAuth1Credentials</value>
<value>updateSharedOAuth1Credentials</value>
<value>deletePersonalOAuth1Credentials</value>
<value>deleteSharedOAuth1Credentials</value>
</list>
</property>
</bean>
<bean id="oauth1CredentialsStoreService" class="org.alfresco.repo.oauth1.OAuth1CredentialsStoreServiceImpl">
<property name="remoteCredentialsService">
<ref bean="RemoteCredentialsService" />
</property>
</bean>
</beans>

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="OAuth2CredentialsStoreService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.service.cmr.oauth2.OAuth2CredentialsStoreService</value>
</property>
<property name="target">
<ref bean="oauth2CredentialsStoreService"/>
</property>
<property name="interceptorNames">
<list>
<idref bean="oauth2CredentialsStoreServiceReadTxnAdvisor"/>
<idref bean="oauth2CredentialsStoreServiceWriteTxnAdvisor"/>
<idref bean="AuditMethodInterceptor"/>
<idref bean="exceptionTranslator"/>
<idref bean="oauth2SCredentialsStoreService_security"/>
</list>
</property>
</bean>
<bean id="oauth2SCredentialsStoreService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="afterInvocationManager">
<ref bean="afterInvocationManager"/>
</property>
<property name="objectDefinitionSource">
<value>
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
</value>
</property>
</bean>
<bean id="oauth2CredentialsStoreServiceReadTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref bean="retryingReadTxnAdvice"/>
</property>
<property name="mappedNames">
<list>
<value>getPersonalOAuth2Credentials</value>
<value>listSharedOAuth2Credentials</value>
<value>updateCredentialsAuthenticationSucceeded</value>
</list>
</property>
</bean>
<bean id="oauth2CredentialsStoreServiceWriteTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref bean="retryingWriteTxnAdvice"/>
</property>
<property name="mappedNames">
<list>
<value>storePersonalOAuth2Credentials</value>
<value>storeSharedOAuth2Credentials</value>
<value>updateSharedOAuth2Credentials</value>
<value>deletePersonalOAuth2Credentials</value>
<value>deleteSharedOAuth2Credentials</value>
</list>
</property>
</bean>
<bean id="oauth2CredentialsStoreService" class="org.alfresco.repo.oauth2.OAuth2CredentialsStoreServiceImpl">
<property name="remoteCredentialsService">
<ref bean="RemoteCredentialsService" />
</property>
</bean>
</beans>

View File

@@ -64,6 +64,7 @@
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>
<property name="namespaceService" ref="NamespaceService"/> <property name="namespaceService" ref="NamespaceService"/>
<property name="dictionaryService" ref="DictionaryService"/> <property name="dictionaryService" ref="DictionaryService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="repositoryHelper" ref="repositoryHelper" /> <property name="repositoryHelper" ref="repositoryHelper" />
<property name="credentialsFactories"> <property name="credentialsFactories">
<map> <map>

View File

@@ -489,6 +489,8 @@
<!-- AVM virtualization view of all stores/versions for WCM --> <!-- AVM virtualization view of all stores/versions for WCM -->
<!-- virtual view stores filter can be any of the following: normal, site, staging, author, preview --> <!-- virtual view stores filter can be any of the following: normal, site, staging, author, preview -->
<!-- AVM context deprecated - uncomment to add back
<bean class="org.alfresco.filesys.avm.AVMContext"> <bean class="org.alfresco.filesys.avm.AVMContext">
<property name="deviceName"> <property name="deviceName">
<value>${filesystem.avm.name}</value> <value>${filesystem.avm.name}</value>
@@ -500,6 +502,7 @@
<value>${filesystem.avm.stores}</value> <value>${filesystem.avm.stores}</value>
</property> </property>
</bean> </bean>
-->
</list> </list>
</property> </property>
</bean> </bean>

View File

@@ -4,6 +4,7 @@ filesystem.acl.global.defaultAccessLevel=
# AVM filesystem context # AVM filesystem context
filesystem.avm.name=AVM filesystem.avm.name=AVM
# Are the virtual views enabled
filesystem.avm.enabled=true filesystem.avm.enabled=true
# virtual view stores filter can be any of the following: normal, site, staging, author, preview # virtual view stores filter can be any of the following: normal, site, staging, author, preview
filesystem.avm.stores=site,staging,author filesystem.avm.stores=site,staging,author

View File

@@ -246,8 +246,8 @@ public class FTPServerTest extends TestCase
assertTrue(FTPReply.isPositiveCompletion(reply)); assertTrue(FTPReply.isPositiveCompletion(reply));
// expect /Alfresco directory // expect /Alfresco directory
// /AVM directory // /AVM directory - avm removed
assertTrue(files.length == 2); assertTrue(files.length == 1);
boolean foundAVM=false; boolean foundAVM=false;
boolean foundAlfresco=false; boolean foundAlfresco=false;
@@ -265,7 +265,8 @@ public class FTPServerTest extends TestCase
foundAlfresco=true; foundAlfresco=true;
} }
} }
assertTrue(foundAVM); // AVM mount point removed
//assertTrue(foundAVM);
assertTrue(foundAlfresco); assertTrue(foundAlfresco);
// Change to Alfresco Dir that we know exists // Change to Alfresco Dir that we know exists

View File

@@ -242,10 +242,6 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean
// Load heart-beat special service (even if disabled at the moment) // Load heart-beat special service (even if disabled at the moment)
heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat"); heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat");
for(LicenseChangeHandler handler : deferredHandlers)
{
licenseService.registerOnLicenseChange(handler);
}
// Now listen for future license changes // Now listen for future license changes
licenseService.registerOnLicenseChange(this); licenseService.registerOnLicenseChange(this);
@@ -677,19 +673,4 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean
LicenseMode.UNKNOWN); LicenseMode.UNKNOWN);
} }
} }
Set<LicenseChangeHandler> deferredHandlers = new HashSet<LicenseChangeHandler>();
@Override
public void registerOnLicenseChange(LicenseChangeHandler callback)
{
if(licenseService != null)
{
licenseService.registerOnLicenseChange(callback);
}
else
{
deferredHandlers.add(callback);
}
}
} }

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<ChildAssociationRef> 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<ChildAssociationRef> 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<NodeRef, Boolean> getOrCreateSystemChildContainer(final QName childName,
final NodeService nodeService, final Repository repositoryHelper)
{
NodeRef container = getSystemChildContainer(childName, nodeService, repositoryHelper);
if (container != null)
{
return new Pair<NodeRef,Boolean>(container, Boolean.FALSE);
}
// Create
container = AuthenticationUtil.runAsSystem(new RunAsWork<NodeRef>() {
@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<NodeRef,Boolean>(container, Boolean.TRUE);
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth1CredentialsInfo> 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<OAuth1CredentialInfo>
*/
@Override
public List<OAuth1CredentialsInfo> listSharedOAuth1Credentials(String remoteSystemId)
throws NoSuchSystemException
{
PagingRequest paging = new PagingRequest(CannedQueryPageDetails.DEFAULT_PAGE_SIZE);
@SuppressWarnings("unchecked")
PagingResults<OAuth1CredentialsInfo> pagingResults = (PagingResults<OAuth1CredentialsInfo>) 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<OAuth1CredentialsInfo> 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);
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth1CredentialsInfo> 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<OAuth1CredentialsInfo> 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<OAuth1CredentialsInfo> 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<OAuth1CredentialsInfo> sharedCredentials = oauth1CredentialsStoreService.listSharedOAuth1Credentials(RemoteSystemId);
OAuth1CredentialsInfo oAuth1CredentialsInfo = sharedCredentials.get(0);
oauth1CredentialsStoreService.deleteSharedOAuth1Credentials(RemoteSystemId, oAuth1CredentialsInfo);
}
@Test
public void testDeleteSharedOAuth1Credentials()
{
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE);
List<OAuth1CredentialsInfo> 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<Void>()
{
@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<Void>()
{
@Override
public Void execute() throws Throwable
{
if (personService.personExists(userName))
{
personService.deletePerson(userName);
}
return null;
}
});
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth2CredentialsInfo> 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<OAuth2CredentialInfo>
*/
@Override
public List<OAuth2CredentialsInfo> listSharedOAuth2Credentials(String remoteSystemId)
throws NoSuchSystemException
{
PagingRequest paging = new PagingRequest(CannedQueryPageDetails.DEFAULT_PAGE_SIZE);
@SuppressWarnings("unchecked")
PagingResults<OAuth2CredentialsInfo> pagingResults = (PagingResults<OAuth2CredentialsInfo>) 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<OAuth2CredentialsInfo> 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);
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth2CredentialsInfo> 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<OAuth2CredentialsInfo> 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<OAuth2CredentialsInfo> 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<OAuth2CredentialsInfo> sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId);
OAuth2CredentialsInfo oAuth2CredentialsInfo = sharedCredentials.get(0);
oauth2CredentialsStoreService.deleteSharedOAuth2Credentials(RemoteSystemId, oAuth2CredentialsInfo);
}
@Test
public void testDeleteSharedOAuth2Credentials()
{
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE);
List<OAuth2CredentialsInfo> 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<Void>()
{
@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<Void>()
{
@Override
public Void execute() throws Throwable
{
if (personService.personExists(userName))
{
personService.deletePerson(userName);
}
return null;
}
});
}
}

View File

@@ -27,12 +27,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.EmptyPagingResults; import org.alfresco.query.EmptyPagingResults;
import org.alfresco.query.ListBackedPagingResults; import org.alfresco.query.ListBackedPagingResults;
import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults; import org.alfresco.query.PagingResults;
import org.alfresco.repo.model.Repository; 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;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.dictionary.DictionaryService; 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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException; 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.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -73,6 +74,7 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService
private Repository repositoryHelper; private Repository repositoryHelper;
private NodeService nodeService; private NodeService nodeService;
private NamespaceService namespaceService; private NamespaceService namespaceService;
private PermissionService permissionService;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
/** /**
@@ -93,6 +95,11 @@ public class RemoteCredentialsServiceImpl implements RemoteCredentialsService
this.namespaceService = namespaceService; this.namespaceService = namespaceService;
} }
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setDictionaryService(DictionaryService dictionaryService) public void setDictionaryService(DictionaryService dictionaryService)
{ {
this.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 = private static QName SHARED_CREDENTIALS_CONTAINER_QNAME =
QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, SHARED_CREDENTIALS_CONTAINER_NAME); 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) protected NodeRef getSharedContainerNodeRef(boolean required)
{ {
// Grab the root of the repository, for the current tennant // Get the container, if available
final NodeRef root = repositoryHelper.getRootHome(); NodeRef container = SystemNodeUtils.getSystemChildContainer(SHARED_CREDENTIALS_CONTAINER_QNAME, nodeService, repositoryHelper);
// Locate the system folder, in the root // If it's needed, have it created
List<ChildAssociationRef> sysRefs = nodeService.getChildAssocs( if (container == null && required)
root, ContentModel.ASSOC_CHILDREN, SYSTEM_FOLDER_QNAME);
if (sysRefs.size() != 1)
{ {
throw new IllegalStateException("System folder missing / duplicated! Found " + sysRefs); // Lock and create
} Pair<NodeRef,Boolean> details = null;
final NodeRef system = sysRefs.get(0).getChildRef(); synchronized (this)
// Find the shared credentials container, under system
List<ChildAssociationRef> 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);
NodeRef container = containerRefs.get(0).getChildRef();
return container;
}
else
{
if (required)
{ {
throw new IllegalStateException("Required System Folder " + SHARED_CREDENTIALS_CONTAINER_QNAME + " is missing!"); details = SystemNodeUtils.getOrCreateSystemChildContainer(SHARED_CREDENTIALS_CONTAINER_QNAME, nodeService, repositoryHelper);
} }
else container = details.getFirst();
// If created, set permissions
// Note - these must be kept in sync with the bootstrap file
if (details.getSecond())
{ {
if (logger.isInfoEnabled()) final NodeRef containerF = container;
logger.info("Required System Folder " + SHARED_CREDENTIALS_CONTAINER_QNAME + " missing, needed for writes"); AuthenticationUtil.runAsSystem(new RunAsWork<Void>() {
return null; @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;
}
});
} }
} }
if (container == 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;
} }
/** /**

View File

@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; 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.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyMap; 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.TemporaryNodes;
import org.alfresco.util.test.junitrules.WellKnownNodes; import org.alfresco.util.test.junitrules.WellKnownNodes;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule; import org.junit.ClassRule;
@@ -130,16 +131,6 @@ public class RemoteCredentialsServicesTest
// Switch to a test shared system container // Switch to a test shared system container
RemoteCredentialsServiceImpl.setSharedCredentialsSystemContainerName(SHARED_SYSTEM_CONTAINER_NAME); 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 @Before public void setupUsers() throws Exception
@@ -154,7 +145,6 @@ public class RemoteCredentialsServicesTest
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE);
} }
/** /**
* Tests that read only methods don't create the shared credentials * Tests that read only methods don't create the shared credentials
* container, but that write ones will do. * container, but that write ones will do.
@@ -165,18 +155,16 @@ public class RemoteCredentialsServicesTest
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER_ONE); 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); NodeRef container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false);
assertNotNull(container); assertEquals(null, container);
assertEquals(0, PUBLIC_NODE_SERVICE.getChildAssocs(container).size());
// Ask for the list of shared remote systems // Ask for the list of shared remote systems
REMOTE_CREDENTIALS_SERVICE.listSharedRemoteSystems(new PagingRequest(10)); 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); container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false);
assertNotNull(container); assertEquals(null, container);
assertEquals(0, PUBLIC_NODE_SERVICE.getChildAssocs(container).size());
// Try to store some credentials // Try to store some credentials
@@ -187,10 +175,11 @@ public class RemoteCredentialsServicesTest
container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false); container = ((RemoteCredentialsServiceImpl)PRIVATE_REMOTE_CREDENTIALS_SERVICE).getSharedContainerNodeRef(false);
assertNotNull(container); assertNotNull(container);
// Should have a marker aspect // Should have a marker aspect, and the specified name
Set<QName> cAspects = PUBLIC_NODE_SERVICE.getAspects(container); Set<QName> cAspects = PUBLIC_NODE_SERVICE.getAspects(container);
assertEquals("Aspect missing, found " + cAspects, true, assertEquals("Aspect missing, found " + cAspects, true,
cAspects.contains(RemoteCredentialsModel.ASPECT_REMOTE_CREDENTIALS_SYSTEM_CONTAINER)); 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 // Should have single node in it
assertEquals(1, PUBLIC_NODE_SERVICE.getChildAssocs(container).size()); assertEquals(1, PUBLIC_NODE_SERVICE.getChildAssocs(container).size());
@@ -905,6 +894,16 @@ public class RemoteCredentialsServicesTest
deleteUser(TEST_USER_THREE); 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. * Deletes the specified NodeRefs, if they exist.
* @param nodesToDelete * @param nodesToDelete

View File

@@ -26,6 +26,7 @@ import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService; import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.node.SystemNodeUtils;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; 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 * Gets the system workflow container for storing workflow related items
* *
* TODO Replace this with calls to {@link SystemNodeUtils}
*
* @return the system workflow container * @return the system workflow container
*/ */
private NodeRef getSystemWorkflowContainer() private NodeRef getSystemWorkflowContainer()

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth1CredentialsInfo> 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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<OAuth2CredentialsInfo> 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);
}

View File

@@ -115,9 +115,4 @@ public interface DescriptorService
*/ */
public String loadLicense(); public String loadLicense();
/**
* Register a callback that gets called when a license changes.
*/
public void registerOnLicenseChange(LicenseChangeHandler callback);
} }