REPO-3176: Initial copy of community pages from architecture map and collapsed index page

This commit is contained in:
dcaruana
2018-01-12 13:46:53 +00:00
parent 0f7e8603d4
commit 5f9363a854
92 changed files with 5710 additions and 0 deletions

69
docs/README.md Normal file
View File

@@ -0,0 +1,69 @@
# Community Technical Documentation Index
## Repository
### Meta-data Services
* [Node Storage and Retrieval](./node-storage-and-retrieval)
* Dictionary
* Files and Folders
* Smart Folders
* [Versions](./versions)
* Permissions
* Tagging
* Multilingual Content
### Content Store
* Content Storage and Retrieval
### Rules Engine
* Rules
* Actions
### Workflow
* Embedded Activiti
### Transformation
* Renditions
### Content Analysis
* Meta-data Extraction
### File Protocols
* CIFS Protocol
* FTP Protocol
* WebDAV Protocol
### Application Protocols
* IMAP Protocol
* Office Protocols
### Scripting
* JavaScript API
* Freemarker API
### Sync and Transfer
* Content Replication
* Content Transfer
### Event Log
* Audit
* Log Messages
### Identity Provider
* [Authentication](./authentication)
* [Identity](./identity)
* LDAP Sync
### Deployment
* Installer
* MMT
* Patch
### Messaging
* Messages and Topics
* [Queue](./queue) (FUTURE)
### Infrastructure
* Module Framework
* Policies and Behaviours
* Multi-tenancy

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,41 @@
@startuml
title Audit and Attributes - High Level Entities
skinparam linetype ortho
rectangle AuditDAO #lightgrey {
rectangle AuditApplication #orange
rectangle AuditModel #white
rectangle ModelContent #white
rectangle AuditEntry #white
}
rectangle PropertyValueDAO #lightgrey {
rectangle Attribute #orange
rectangle ComplexProperty #white
rectangle SimpleProperty #white
rectangle Value #white
rectangle Caches #white {
rectangle PropertyUniqueContextSharedCache #white
rectangle PropertyClassSharedCache #white
rectangle PropertyValueSharedCache #white
}
}
AuditApplication --* AuditModel
AuditApplication --* AuditEntry
AuditModel -- ModelContent
PropertyClassSharedCache ->SimpleProperty
PropertyValueSharedCache ->SimpleProperty
PropertyUniqueContextSharedCache ->Attribute
SimpleProperty .. Value :value
SimpleProperty -- Attribute: keys (1 to 3)
ComplexProperty -- SimpleProperty
ComplexProperty -- AuditEntry :audit values
ComplexProperty -- AuditApplication :disabled paths
Attribute -- ComplexProperty
center footer Copyright 2016 Alfresco Software Inc
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

View File

@@ -0,0 +1,337 @@
@startuml
' Generated using https://github.com/juanmf/Java2PlantUML
left to right direction
' Participants
class org.alfresco.jlan.server.auth.AuthContext {
--
+ AuthContext()
}
interface org.springframework.beans.factory.InitializingBean {
--
+ afterPropertiesSet() : void
}
interface org.alfresco.repo.transaction.RetryingTransactionHelper$RetryingTransactionCallback <Result extends c Object> {
--
+ execute() : Object
}
interface org.alfresco.jlan.server.SessionListener {
--
+ sessionClosed(c SrvSession) : void
+ sessionCreated(c SrvSession) : void
+ sessionLoggedOn(c SrvSession) : void
}
interface org.alfresco.filesys.auth.cifs.package-info {
--
}
interface javax.security.auth.callback.CallbackHandler {
--
+ handle(c Callback;) : void
}
class org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator {
+ DefaultSessionTmo : int
+ MaxCheckInterval : int
+ MaxSessionTmo : int
+ MinCheckInterval : int
+ MinSessionTmo : int
+ PassthruKeepAliveInterval : long
- NTLM_FLAGS : int
- logger : i Log
- m_localPassThruServers : boolean
- m_passthruServers : c PassthruServers
- m_sessions : Hashtable< String, PassthruDetails>
--
+ PassthruCifsAuthenticator()
# validateAuthenticationMode() : boolean
+ authenticateShareConnect(c ClientInfo, c SharedDevice, c String, c SrvSession) : int
+ authenticateUser(c ClientInfo, c SrvSession, int) : int
+ closeAuthenticator() : void
+ generateNegotiateResponse(c SMBSrvSession, c SMBSrvPacket, boolean) : void
+ getAuthContext(c SMBSrvSession) : AuthContext
+ getServerCapabilities() : int
+ getSessions() : Hashtable
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ processAlfrescoSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
+ processSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
+ sessionClosed(c SrvSession) : void
+ sessionCreated(c SrvSession) : void
+ sessionLoggedOn(c SrvSession) : void
+ setPassthruServers(c PassthruServers) : void
- doNTLMv1Logon(c SMBSrvSession, c ClientInfo, c Type3NTLMMessage) : void
- doNtlmsspSessionSetup(c SMBSrvSession, c ClientInfo, class [B, int, int, boolean) : [B
}
interface org.alfresco.repo.security.authentication.AuthenticationUtil$RunAsWork <Result extends c Object> {
--
+ doWork() : Object
}
class org.alfresco.filesys.auth.cifs.AuthTokenAuthContext {
- m_token : c NTLMPassthruToken
--
+ AuthTokenAuthContext(c NTLMPassthruToken)
+ getChallenge() : [B
+ getToken() : NTLMPassthruToken
}
class org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase {
# logger : i Log
# m_md4Encoder : i MD4PasswordEncoder
- active : boolean
- authenticationComponent : i AuthenticationComponent
- authenticationService : i AuthenticationService
- authorityService : i AuthorityService
- diskInterface : i DiskInterface
- nodeService : i NodeService
- personService : i PersonService
- transactionService : i TransactionService
--
+ CifsAuthenticatorBase()
# checkForAdminUserName(c ClientInfo) : void
# doGuestLogon(c ClientInfo, c SrvSession) : void
# doInTransaction( RetryingTransactionHelper$RetryingTransactionCallback<T>) : Object
# getAuthenticationComponent() : AuthenticationComponent
# getAuthenticationService() : AuthenticationService
# getAuthorityService() : AuthorityService
# getHomeFolderForUser(c ClientInfo) : void
# getNTLMAuthenticator() : NLTMAuthenticator
# getNodeService() : NodeService
# getPersonService() : PersonService
# validateAuthenticationMode() : boolean
+ afterPropertiesSet() : void
+ destroy() : void
+ initialize() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ isActive() : boolean
+ mapUserNameToPerson(c String, boolean) : String
+ setActive(boolean) : void
+ setAuthenticationComponent(i AuthenticationComponent) : void
+ setAuthenticationService(i AuthenticationService) : void
+ setAuthorityService(i AuthorityService) : void
+ setCurrentUser(c ClientInfo) : void
+ setDiskInterface(i DiskInterface) : void
+ setNodeService(i NodeService) : void
+ setPersonService(i PersonService) : void
+ setTransactionService(i TransactionService) : void
- getTransactionService() : TransactionService
}
class org.alfresco.jlan.server.auth.ChallengeAuthContext {
# m_challenge : class [B
--
+ ChallengeAuthContext()
+ getChallenge() : [B
}
class org.alfresco.jlan.server.auth.CifsAuthenticator {
# GUEST_USERNAME : c String
# m_config : i ServerConfigurationAccessor
# m_random : c Random
- m_accessMode : int
- m_allowGuest : boolean
- m_debug : boolean
- m_dialects : c DialectSelector
- m_encryptor : c PasswordEncryptor
- m_extendedSecurity : boolean
- m_guestUserName : c String
- m_mapToGuest : boolean
- m_securityMode : int
- m_sessCleanup : boolean
--
+ CifsAuthenticator()
# convertPassword(c String) : [B
# doGuestLogon(c ClientInfo, c SrvSession) : void
# generateEncryptedPassword(c String, class [B, int, c String, c String) : [B
# getEncryptor() : PasswordEncryptor
# getStatusAsString(int) : String
# mapClientAddressToDomain(c InetAddress) : String
# setExtendedSecurity(boolean) : void
# setSecurityMode(int) : void
# validatePassword(c UserAccount, c ClientInfo, c AuthContext, int) : boolean
+ allowGuest() : boolean
+ authenticateShareConnect(c ClientInfo, c SharedDevice, c String, c SrvSession) : int
+ authenticateUser(c ClientInfo, c SrvSession, int) : int
+ authenticateUserPlainText(c ClientInfo, c SrvSession) : int
+ closeAuthenticator() : void
+ generateNegotiateResponse(c SMBSrvSession, c SMBSrvPacket, boolean) : void
+ getAccessMode() : int
+ getAuthContext(c SMBSrvSession) : AuthContext
+ getCIFSConfig() : CIFSConfigSection
+ getEnabledDialects() : DialectSelector
+ getEncryptionKeyLength() : int
+ getGuestUserName() : String
+ getSecurityMode() : int
+ getServerCapabilities() : int
+ getUserDetails(c String) : UserAccount
+ getsecurityConfig() : SecurityConfigSection
+ hasDebug() : boolean
+ hasExtendedSecurity() : boolean
+ hasSessionCleanup() : boolean
+ initialize() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ mapUnknownUserToGuest() : boolean
+ processSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
+ setAccessMode(int) : void
+ setAllowGuest(boolean) : void
+ setConfig(i ServerConfigurationAccessor) : void
+ setCurrentUser(c ClientInfo) : void
+ setDebug(boolean) : void
+ setGuestUserName(c String) : void
+ setMapToGuest(boolean) : void
+ setSessionCleanup(boolean) : void
+ toString() : String
}
interface org.alfresco.jlan.server.auth.ICifsAuthenticator {
+ AUTH_ACCDISABLED : int
+ AUTH_ALLOW : int
+ AUTH_BADPASSWORD : int
+ AUTH_BADUSER : int
+ AUTH_DISALLOW : int
+ AUTH_GUEST : int
+ AUTH_PASSEXPIRED : int
+ LANMAN : int
+ NTLM1 : int
+ NTLM2 : int
+ NoAccess : int
+ ReadOnly : int
+ SHARE_MODE : int
+ STANDARD_CHALLENGE_LEN : int
+ STANDARD_PASSWORD_LEN : int
+ USER_MODE : int
+ Writeable : int
--
+ authenticateShareConnect(c ClientInfo, c SharedDevice, c String, c SrvSession) : int
+ authenticateUser(c ClientInfo, c SrvSession, int) : int
+ closeAuthenticator() : void
+ generateNegotiateResponse(c SMBSrvSession, c SMBSrvPacket, boolean) : void
+ getAccessMode() : int
+ getEncryptionKeyLength() : int
+ getSecurityMode() : int
+ getServerCapabilities() : int
+ hasExtendedSecurity() : boolean
+ processSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
+ setCurrentUser(c ClientInfo) : void
}
class org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator {
# logger : i Log
- LoginConfigEntry : c String
- NTLM_FLAGS : int
- disableNTLM : boolean
- kerberosDebug : boolean
- m_acceptNTLMv1 : boolean
- m_accountName : c String
- m_enableTicketCracking : boolean
- m_krbRealm : c String
- m_loginContext : c LoginContext
- m_loginEntryName : c String
- m_mecListMIC : c String
- m_mechTypes : Vector< Oid>
- m_negTokenInit : class [B
- m_password : c String
- m_stripKerberosUsernameSuffix : boolean
- m_useRawNTLMSSP : boolean
--
+ EnterpriseCifsAuthenticator()
+ generateNegotiateResponse(c SMBSrvSession, c SMBSrvPacket, boolean) : void
+ getEncryptionKeyLength() : int
+ getServerCapabilities() : int
+ handle(c Callback;) : void
+ initialize() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ processSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
+ setDisableNTLM(boolean) : void
+ setDisallowNTLMv1(boolean) : void
+ setEnableTicketCracking(boolean) : void
+ setJaasConfigEntryName(c String) : void
+ setKerberosDebug(boolean) : void
+ setPassword(c String) : void
+ setRealm(c String) : void
+ setStripKerberosUsernameSuffix(boolean) : void
+ setUseSPNEGO(boolean) : void
- acceptNTLMv1Logon() : boolean
- doHashedPasswordLogon(c SMBSrvSession, c SMBSrvPacket) : void
- doKerberosLogon(c SMBSrvSession, c NegTokenInit, c ClientInfo) : NegTokenTarg
- doNTLMv1Logon(c SMBSrvSession, c ClientInfo) : void
- doNTLMv1Logon(c SMBSrvSession, c ClientInfo, c Type3NTLMMessage) : void
- doNTLMv2Logon(c SMBSrvSession, c ClientInfo) : void
- doNTLMv2Logon(c SMBSrvSession, c ClientInfo, c Type3NTLMMessage) : void
- doNTLMv2SessionKeyLogon(c SMBSrvSession, c ClientInfo, c Type3NTLMMessage) : void
- doNtlmsspSessionSetup(c SMBSrvSession, c ClientInfo, class [B, int, int, boolean) : [B
- doSpnegoSessionSetup(c SMBSrvSession, c ClientInfo, class [B, int, int, boolean) : [B
- getNegTokenInit() : [B
- isKerberosEnabled() : boolean
- normalizeUserId(c String) : String
- processAlfrescoSessionSetup(c SMBSrvSession, c SMBSrvPacket) : void
- useRawNTLMSSP() : boolean
}
interface org.springframework.beans.factory.DisposableBean {
--
+ destroy() : void
}
class org.alfresco.filesys.auth.cifs.AlfrescoCifsAuthenticator {
--
+ AlfrescoCifsAuthenticator()
# validateAuthenticationMode() : boolean
+ authenticateShareConnect(c ClientInfo, c SharedDevice, c String, c SrvSession) : int
+ authenticateUser(c ClientInfo, c SrvSession, int) : int
+ getAuthContext(c SMBSrvSession) : AuthContext
- doMD4UserAuthentication(c ClientInfo, c SrvSession, int) : int
- doPassthruUserAuthentication(c ClientInfo, c SrvSession, int) : int
}
interface org.alfresco.repo.management.subsystems.ActivateableBean {
--
+ isActive() : boolean
}
' Relations
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.security.AuthenticationService : authenticationService: i AuthenticationService
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.security.PersonService : personService: i PersonService
org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator "1" o-left- "1" org.apache.commons.logging.Log : logger: i Log
org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator "1" o-left- "*" org.ietf.jgss.Oid : m_mechTypes: Vector< Oid>
org.alfresco.jlan.server.auth.CifsAuthenticator "1" o-left- "1" org.alfresco.jlan.server.auth.PasswordEncryptor : m_encryptor: c PasswordEncryptor
org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator "1" o-left- "1" org.apache.commons.logging.Log : logger: i Log
org.alfresco.jlan.server.auth.CifsAuthenticator "1" o-left- "1" java.util.Random : m_random: c Random
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.service.transaction.TransactionService : transactionService: i TransactionService
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.jlan.server.filesys.DiskInterface : diskInterface: i DiskInterface
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.apache.commons.logging.Log : logger: i Log
org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator "1" o-left- "*" org.alfresco.jlan.server.auth.passthru.PassthruDetails : m_sessions: Hashtable< String, PassthruDetails>
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.repo.security.authentication.AuthenticationComponent : authenticationComponent: i AuthenticationComponent
org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator "1" o-left- "1" javax.security.auth.login.LoginContext : m_loginContext: c LoginContext
org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator "1" o-left- "1" org.alfresco.jlan.server.auth.passthru.PassthruServers : m_passthruServers: c PassthruServers
org.alfresco.jlan.server.auth.CifsAuthenticator "1" o-left- "1" org.alfresco.jlan.smb.DialectSelector : m_dialects: c DialectSelector
org.alfresco.jlan.server.auth.CifsAuthenticator "1" o-left- "1" org.alfresco.jlan.server.config.ServerConfigurationAccessor : m_config: i ServerConfigurationAccessor
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.repository.NodeService : nodeService: i NodeService
org.alfresco.filesys.auth.cifs.AuthTokenAuthContext "1" o-left- "1" org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken : m_token: c NTLMPassthruToken
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.repo.security.authentication.MD4PasswordEncoder : m_md4Encoder: i MD4PasswordEncoder
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.security.AuthorityService : authorityService: i AuthorityService
org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator -up|> org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase
org.alfresco.filesys.auth.cifs.AlfrescoCifsAuthenticator -up|> org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase
org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator -up|> org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase -up|> org.alfresco.jlan.server.auth.CifsAuthenticator
org.alfresco.jlan.server.auth.ChallengeAuthContext -up|> org.alfresco.jlan.server.auth.AuthContext
org.alfresco.filesys.auth.cifs.AuthTokenAuthContext -up|> org.alfresco.jlan.server.auth.ChallengeAuthContext
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase ..up|> org.springframework.beans.factory.DisposableBean
org.alfresco.jlan.server.auth.CifsAuthenticator ..up|> org.alfresco.jlan.server.auth.ICifsAuthenticator
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase ..up|> org.springframework.beans.factory.InitializingBean
org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator ..up|> javax.security.auth.callback.CallbackHandler
org.alfresco.filesys.auth.cifs.CifsAuthenticatorBase ..up|> org.alfresco.repo.management.subsystems.ActivateableBean
org.alfresco.filesys.auth.cifs.PassthruCifsAuthenticator ..up|> org.alfresco.jlan.server.SessionListener
' Notes
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View File

@@ -0,0 +1,113 @@
@startuml
' Generated using https://github.com/juanmf/Java2PlantUML
left to right direction
' Participants
interface org.alfresco.jlan.ftp.FTPAuthenticator {
--
+ authenticateUser(c ClientInfo, c FTPSrvSession) : boolean
+ closeAuthenticator() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
}
interface org.springframework.beans.factory.DisposableBean {
--
+ destroy() : void
}
interface org.alfresco.filesys.auth.ftp.package-info {
--
}
interface org.alfresco.repo.management.subsystems.ActivateableBean {
--
+ isActive() : boolean
}
class org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase {
# logger : i Log
# serverConfiguration : i ServerConfigurationAccessor
- active : boolean
- authenticationComponent : i AuthenticationComponent
- authenticationService : i AuthenticationService
- authorityService : i AuthorityService
- transactionService : i TransactionService
--
+ FTPAuthenticatorBase()
# checkForAdminUserName(c ClientInfo) : void
# createTransaction() : UserTransaction
# getAuthenticationComponent() : AuthenticationComponent
# getAuthenticationService() : AuthenticationService
# getAuthorityService() : AuthorityService
# getNTLMAuthenticator() : NLTMAuthenticator
# getTransactionService() : TransactionService
+ authenticateUser(c ClientInfo, c FTPSrvSession) : boolean
+ closeAuthenticator() : void
+ destroy() : void
+ initialize() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ isActive() : boolean
+ setActive(boolean) : void
+ setAuthenticationComponent(i AuthenticationComponent) : void
+ setAuthenticationService(i AuthenticationService) : void
+ setAuthorityService(i AuthorityService) : void
+ setConfig(i ServerConfigurationAccessor) : void
+ setTransactionService(i TransactionService) : void
}
class org.alfresco.filesys.auth.ftp.PassthruFtpAuthenticator {
+ DefaultSessionTmo : int
+ MaxCheckInterval : int
+ MaxSessionTmo : int
+ MinCheckInterval : int
+ MinSessionTmo : int
+ PassthruKeepAliveInterval : long
- m_localPassThruServers : boolean
- m_passthruServers : c PassthruServers
- m_passwordEncryptor : c PasswordEncryptor
--
+ PassthruFtpAuthenticator()
# doGuestLogon(c AlfrescoClientInfo, c SrvSession) : void
# getSecurityConfig() : SecurityConfigSection
# mapClientAddressToDomain(c InetAddress) : String
+ authenticateUser(c ClientInfo, c FTPSrvSession) : boolean
+ closeAuthenticator() : void
+ initialize() : void
+ initialize(c ServerConfiguration, i ConfigElement) : void
+ setPassthruServers(c PassthruServers) : void
- doPassthruUserAuthentication(c ClientInfo, c SrvSession) : boolean
}
class org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator {
# m_encryptor : c PasswordEncryptor
# m_md4Encoder : i MD4PasswordEncoder
--
+ AlfrescoFtpAuthenticator()
# doGuestLogon(c AlfrescoClientInfo, c SrvSession) : void
+ authenticateUser(c ClientInfo, c FTPSrvSession) : boolean
}
' Relations
org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator "1" o-left- "1" org.alfresco.repo.security.authentication.MD4PasswordEncoder : m_md4Encoder: i MD4PasswordEncoder
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.alfresco.service.transaction.TransactionService : transactionService: i TransactionService
org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator "1" o-left- "1" org.alfresco.jlan.server.auth.PasswordEncryptor : m_encryptor: c PasswordEncryptor
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.apache.commons.logging.Log : logger: i Log
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.alfresco.jlan.server.config.ServerConfigurationAccessor : serverConfiguration: i ServerConfigurationAccessor
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.alfresco.repo.security.authentication.AuthenticationComponent : authenticationComponent: i AuthenticationComponent
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.security.AuthorityService : authorityService: i AuthorityService
org.alfresco.filesys.auth.ftp.PassthruFtpAuthenticator "1" o-left- "1" org.alfresco.jlan.server.auth.PasswordEncryptor : m_passwordEncryptor: c PasswordEncryptor
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase "1" o-left- "1" org.alfresco.service.cmr.security.AuthenticationService : authenticationService: i AuthenticationService
org.alfresco.filesys.auth.ftp.PassthruFtpAuthenticator "1" o-left- "1" org.alfresco.jlan.server.auth.passthru.PassthruServers : m_passthruServers: c PassthruServers
org.alfresco.filesys.auth.ftp.AlfrescoFtpAuthenticator -up|> org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase
org.alfresco.filesys.auth.ftp.PassthruFtpAuthenticator -up|> org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase ..up|> org.alfresco.jlan.ftp.FTPAuthenticator
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase ..up|> org.alfresco.repo.management.subsystems.ActivateableBean
org.alfresco.filesys.auth.ftp.FTPAuthenticatorBase ..up|> org.springframework.beans.factory.DisposableBean
' Notes
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
## Authentication
![Completeness Badge](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square)
![Version Badge](https://img.shields.io/badge/Product-Alfresco_Content_Services_5.2-blue.svg?colorB=2196f3&style=flat-square?colorB=2196f3&style=flat-square)
### Purpose
The purpose of this sub-component is to authenticate users.
***
### Overview
In order to use any service in Alfresco, a user must be authenticated.
Alfresco provides a default Authentication implementation that uses userid's and passwored
managed by Alfresco. But, importantly, Alfresco also allows the customer
to integrate with a number of external Authentication providers including
* Active Directory
* Kerberos
* NTLM
* LDAP
***
### Artifacts and Guidance
* Source Code Links:
* https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root/enterpriseprojects/repository/source/java/
* https://github.com/Alfresco/alfresco-data-model/tree/master/src/main/java/org/alfresco/repo/security/authentication
* License: LGPL
* Issue Tracker Link: https://issues.alfresco.com/jira/issues/?jql=project%3DREPO
* Documentation Link: http://docs.alfresco.com/5.2/concepts/auth-intro.html
* Contribution Model: Alfresco Open Source
***
### Prerequisite Knowledge
* [Acegi](http://springinpractice.com/2008/02/26/acegi-overview)
* [CAS](https://en.wikipedia.org/wiki/Central_Authentication_Service)
* [JAAS](http://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html)
* [Kerberos](https://msdn.microsoft.com/en-us/library/bb742516.aspx)
* [LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
* [NTLM](https://msdn.microsoft.com/en-us/library/windows/desktop/aa378749(v=vs.85).aspx)
***
### Design
#### Default Authentication
In order to use any service in Alfresco, a user or client must be authenticated.
There is a default implementation provided that authenticates users based on a userid and password, where the userid's and passwords
are stored in the Alfresco repository.
#### Chaining
Most production systems that use Alfresco will rely upon more secure approaches, so Alfresco also allows the
customer to integrate a choice of existing authentication providers, including *Active Directory*, *Kerberos*, *LDAP* and *NTLM*.
The implementation of each such Authorization provider is delivered as a separate Alfresco Subsystem.
The Subsystems are chained together as an ordered list of providers each of which, in turn, will be given
a chance to authenticate the user, until the user is authenticated or there are no providers, in
which case the authentication of the user fails.
#### Component Model
#### Data Model
![Data Model](../resource/class/org.alfresco.repo.security.authentication.png)
#### Data Dictionary
#### Flows
##### Login Flow
##### Default Authentication Login Flow
This flow starts when the Login Post request
depicted in [Client Login](../../../share/share-app/resource/sequence/client-login-sequence.png) reaches the repository tier.
![Default Authentication Login Flow](./resource/sequence/login-using-default-authentication.png)
##### Default Authentication Logoff Flow
![Note](https://img.shields.io/badge/Editor-TODO-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
##### Kerberos Authentication Login Flow
![Note](https://img.shields.io/badge/Editor-TODO-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
##### NTLM Authentication Login Flow
![Note](https://img.shields.io/badge/Editor-TODO-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
#### Class Diagram
![Authentication](../resource/class/org.alfresco.service.cmr.security.class.png)
### APIs and Interfaces
#### Java
The sub-component provides a definition and implementation of the following
Java interfaces.
* **Authentication Service**
**Note**: This service is part of the Public API
* authenticate using a user name and password
* authenticate using a ticket
* create, update and delete authentication information
* clear the current authentication
* invalidate a ticket
* get the username for who is currently authenticated
* get a ticket for subsequent re-authentication
* determine if the current user is 'the system user
* **MutableAuthenticationService*
In addition, there are a number of related interfaces that provide
a way to manage users and groups and permissions
![Note](https://img.shields.io/badge/Editor-Note-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
*This information should probably move to the Identity sub-component after the content already there (future design thoughts)
is relocated*
* **Authority Service**
**Note**: This service is part of the Public API
* create authority identifiers
* query for authority identifiers
* delete authority identifiers
* organize authority identifiers into hierarchies
* query against authority identifiers hierarchies
* find all the authorties that apply to the current authenticated user
* determine if the current authenticated user has admin rights
* **Ownable Service**
**Note**: This service is **not** part of the Public API
* determine the owner of a node;
* set the owner of a node;
* determine if a node has an owner
* allow the current user to take ownership of a node
* **Person Service**
**Note**: This service is part of the Public API
* obtain a reference to the Person node for a given user name
* determine if a person entry exists for a user
* create missing people entries, with default settings, on demand
* supply a list of mutable properties for each person
* create, delete and update personal information
***
#### REST
The sub-component provides the following REST API
* https://api-explorer.alfresco.com/api-explorer/#/authentication
### Configuration
***
### Performance Considerations
![Note](https://img.shields.io/badge/Editor-TODO-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
Describe Caching of tickets
As mentioned in the *Security Considerations* section, Bcrypt can be used to encrypt passwords. Note that is
is much slower than MD4 or SHA-256.
***
### Security Considerations
***
In the case of the default Authentication provider, Alfresco is responsible for storing
userid's and passwords. The passwords are stored as hashed values. The default hashing
algorithm used is MD4, but the customer can also elect to use more secure hashing algorithms
include SHA-256 and Bcrypt. The system property *system.preferred.password.encoding* is used
to select which algorithm is used.
### Cloud Considerations
![Note](https://img.shields.io/badge/Editor-TODO-yellow.svg?&style=flat-square?colorB=2196f3&style=flat-square)
Describe OAuth2 for protection of Cloud REST API's.
***

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@@ -0,0 +1,117 @@
@startuml
Title: Default Authentication Login Flow
participant "Repository\nContainer" as W
participant "LoginPost\nbean" as LB
participant "SubsystemChaining\nAuthenticationService" as SCAS
participant "MutableAuthentication\nServiceImpl" as AS
participant "Authentication\nComponentImpl" as AC
participant "PersonServiceImpl" as PS
participant "NodeService" as NS
participant "Authentication\nContextImpl" as ACX
participant "Authentication\nUtil" as AU
participant "InMemoryTicketComponentImpl" as ITC
participant "AuthorityServiceImpl" as AUS
participant "RepositoryAuthenticatedUser" as RAU
participant "RepositoryAuthenticationDao" as RAD
participant "MD4PasswordEncoderImpl" as MPE
participant "RepositoryAuthenticationProvider" as RAP
participant "CompositePasswordEncoder" as CPE
activate W
W->LB: login request <username> <password>
LB->LB: login <username> <password>
LB->SCAS:authenticate <username> <password>
note right of SCAS
allowedUsers and maxUsers check
end note
SCAS->SCAS: preAuthenticationCheck
note right of SCAS
get list of usableAuthenticationServices
and iterates over this list. In
this default case there is a single
service 'alfrescoNtlm'
end note
SCAS->AS: authenticate\n<username> <password>
AS->AC:clearCurrentSecurityContext
AC->ACX:clearCurrentSecurityContext
ACX->AU:clearCurrentSecurityContext
AU->ACX: done
ACX->AC: done
AC->AS: done
AS->ITC:clearCurrentTicket
ITC->AS: done
note right of AS
allowedUsers and maxUsers check
end note
AS->AS: preAuthenticationCheck
note right of AS
Checks cache to detect
Brute Force attack
end note
AS->AS: isUserProtected <username>
AS->AC: authenticate\n<username> <password>
AC->PS:getUserIdentifier <username>
PS->PS:getPersonOrNullImpl
PS->PS:looks for Person\nin Cache
PS->NS:get properties of Person\nand checks if\nneeds to add to cache
PS->AC: username
note right of AC
Checks for guest
end note
AC->AC:isGuestUserName
AC->AC: authenticateImpl <username> <password>
AC->AU: getUserTenant
AU->AC: tenant
group Retrying Transaction
AC->RAD: loadUserByUsername <username>
RAD->RAU: constructor <username> <hashedpassword>
RAD->AC: user details
AC->RAP: isPasswordCorrect\n(UsernamePasswordAuthenticationToken, user details)
RAP->CPE: matches
CPE->MPE:isPasswordValid
MPE->MPE:encodeInternal
MPE->MPE: true
MPE->RAP: true
RAP->AC: true
AC->AUS: isAdminAuthority
AUS->AC: false
AC->PS:getPersonOrNullImpl
PS->PS:looks for Person\nin Cache
PS->NS:get properties of Person\nand checks if\nneeds to add to cache
NS->PS: properties
PS->AC: username
end
group setCurrentUser <username>
AC->ACX: isSystemUserName <username>
ACX->AC: false
AC->AC: setUserDetails (role=<b>ROLE_AUTHENTICATED</b>)
end
note right of AC
Increment numberSuccessfulAuthentications
end note
AC->AC: onAuthenticate
AC->AS: succeeded
AS->ITC: clearCurrentTicket
ITC->AS: done
AS->ITC: getCurrentTicket (auto create off)
ITC->AS
AS->AS: getNewTicket
AS->AS: preAuthenticationCheck
AS->ITC: getNewTicket
AS->SCAS
SCAS->LB
note right of LB
Put ticket into the model
end note
LB->AS: getCurrentTicket
AS->LB: ticket
LB->W: Login Request Response
note right of W
Authentication TICKET
returned in model
end note
deactivate W
@enduml

View File

@@ -0,0 +1,260 @@
## Identity
![Completeness Badge](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square)
![Version Badge](https://img.shields.io/badge/Version-Future-blue.svg?style=flat-square)
### Purpose
The Identity Component manages the directory of entities (users, groups and systems) that can use Alfresco services, and is also responsible for authenticating such entities.
***
### Overview
***
### Artifacts and Guidance
* Source Code Link: https://github.com/Alfresco/identity-service
* License: LGPL
* Issue Tracker Link: https://issues.alfresco.com/jira/projects/ID
* Documentation Link:
* Contribution Model: Alfresco Closed Source
***
### Prerequisite Knowledge
***
### Design
#### Open Source Offerings
Several Open Source offerings exist in this space. These can be reviewed as possible aternatives for us developing our own implementation.
***
##### Keystone
Keystone is the Identity Service used in the OpenStack Platform. It is written in Python. It provides Authentication and Authorization services, but not User Profile Management services.
Source: https://github.com/openstack/keystone
License: Apache 2.0
Documentation: http://docs.openstack.org/developer/keystone/
***
##### Keycloak
Keycloak is the Identity Service developed by Red Hat. It is written in Java. It provides Authentication, Authorization services, and User Profile Management services.
Source: https://github.com/keycloak/keycloak
License: Apache 2.0
Documentation: http://www.keycloak.org/documentation.html
***
##### Syncope
Syncope is an Identity Service from Apache.
* Written in Java
* Deployed as a set of three war files
* Tested with Tomcat, Glassfish, Payara, Wildfly app servers
* Tested with PostgreSQL, MariaDB, MySQL, Oracle and MS SQL
* Provides User Profile Management Services
* Provides User Authentication Services including both an internal (self-contained) directory as well as integration with external directory systems
* Integrates with Activiti for a user provisioning workflow (see https://syncope.apache.org/apidocs/2.0/org/apache/syncope/core/workflow/activiti/spring/package-frame.html)
* Provides a full REST API, with a Swagger definition file
* Provides an admin console
Source: https://git-wip-us.apache.org/repos/asf/syncope.git
License: Apache 2.0
Documentation: https://syncope.apache.org/docs/index.html
***
##### SCIM
An implementation of SCIM would be a UPM system that seems to satisfy the user stories defined in https://issues.alfresco.com/jira/browse/ID-1.
There are [a number of such implementations](http://www.simplecloud.info), 16 of which are open source implementations.
Greg Melahn assessed SCIM in 2013. See [Architecture Notes](https://docs.google.com/a/alfresco.com/document/d/1JmHrd1AYWn2dyU43_FnFg2XQ69ktn7EIPKpDE3YAjAA/edit?usp=sharing)
***
#### Component Model
There are three principal configurations supported by the Identity Service
1. Internal Directory
This is the out of the box configuration in which the service persists content in a database.
2. External Directory
In this configuration the Identity Service is configured to delegate authentication and user profile storage to an external
service such as LDAP. A database is still used to store configuration data.
3. SAML
In this configuration the Identity Service is configured to delegate authentication and user profile storage to a SAML IdP.
In this configuration the Identity Service is viewed by the IdP as a Service Provider.
These configurations are illustrated below.
![Configurations](./resource/component/is-ecm-bpm-components.png)
#### Data Model
The following are the elements of the Data Model
* **Entity**
This represents the actual person, identified by a guid issued by the Identity Service.
* **User**
This is the user as it is known to an instance of Alfresco or to a system, like Box, that is integrated with Alfresco. A *User* is associated with one, and only one, *Entity*. A *User* is a member of at least one *Group*, and may be a member of multiple *Groups*.
* **Group**
This is a collection of *Users* or other *Groups*. A *Group* may only be a member of one *Group*. Each *Domain* has at least one *Group*, known as *ALL*, which has no parent.
* **Domain**
This represents a Directory, which may either be external (such as an LDAP) or internal (Alfresco).
* **Token**
This is something issued to a *User* that certifies that the *User* has been authenticated
by a *Domain*. Typically the Domain is an external system such as an LDAP which is responsible for
issuing the token.
In the case where Alfresco is authenticating the user because there is no associated external service, the token is issued by the Identity Service
* **System**
This represents the system to which the *User* is associated, such as "Box", "Salesforce" or "Alfresco Cloud".
![Question Badge](https://img.shields.io/badge/Design-Question-red.svg?style=flat-square) Do we really need both *System* and *Domain*?
![Data Model](./resource/data/data-model.png)
#### Data Dictionary
Not applicable
#### Flows
##### Add a User using Alfresco Admin
![Create Alfresco User](./resource/sequence/create-user-alfresco.png)
##### OAuth Flow (Alfresco and Box for example)
![OAuth Flow](./resource/sequence/oauth-flow.png)
##### SAML Flow (The Identity Service uses a SAML IdP for authentication)
This is a somewhat simplified flow in that interactions with the Queuing system are
omitted
![SAML Flow](./resource/sequence/saml-is-flow.png)
##### Use of a Proxy to Manage Alfresco and Activiti tokens
As an interim approach, Mario has proposed the introduction of a proxy that sits in front of both Alfresco and
Activiti to trigger a flow that would cause the Identity service to collect credentials from the
user, collect an alf and act token from Alfresco and Activity using those credentials and then store the tokens
with a generated common token that the client could pass-back as proof of authentication.
The purpose of the proxy in this flow, is to allow the use of the Identity Service in *current* deployments of Alfresco
and Activity where there is no opportunity to update Alfresco or Activiti.
![Common SSO Flow with a Proxy](./resource/sequence/identity-proxy.png)
#### Class Diagram
***
### APIs and Interfaces
#### REST API
![Design](https://img.shields.io/badge/Design-TODO-orange.svg?style=flat-square) Gav to provide a proposal for the CRUD part of this API.
NOTE: This API does not match the data model above, alternative proposed data model diagram TBD.
GET /users
POST /users <- Something close to the [SCIM](http://www.simplecloud.info/specs/draft-scim-core-schema-01.html#anchor8) user representation
GET /users/{id} -> Something close to the [SCIM](http://www.simplecloud.info/specs/draft-scim-core-schema-01.html#anchor8) user representation
GET /users/{id}/groups
GET /users/{id}/identities
GET /users/{id}/tokens (validate token only, checks all identities for user)
PUT & PATCH /users/{id}
DELETE /users/{id}
GET /groups
POST /groups
GET /groups/members
POST /groups/members
POST /tokens
##### Examples
<pre>
POST /users
{
"userName": "gcornwell",
"name": {
"formatted": "Mr. Gavin Paul Cornwell",
"familyName": "Cornwell",
"givenName": "Gavin",
"middleName": "Paul",
"honorificPrefix": "Mr."
},
"displayName": "Gavin Cornwell",
"emails": [
{
"value": "gavin.cornwell@alfresco.com",
"type": "work",
"primary": true
}
],
"identities": [
{
"systemId": "box",
"externalId": "gavinc",
"token": "e9e30dba-f08f-4109-8486-d5c6a331660a"
}
]
}
</pre>
***
### Configuration
***
### Performance Considerations
***
### Security Considerations
***
### Cloud Considerations
***
### Design Questions and Decisions
| Question | Decision | Rationale | Date |
| :----------------|:-----------------------| --------------------------:| ------------:|
| Should we start with existing Open Source (e.g. Keycloak)
|
***
### Quiz

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,59 @@
@startuml
left to right direction
skinparam linetype ortho
rectangle "Internal Directory Configuration" {
actor User as U1
database "Interna]\nDirectory\n(e.g. NoSQL)" as D1
rectangle "Identity Service" as IS1
rectangle "Alfresco" as ALF1
rectangle "Activiti" as ACT1
U1---->ACT1
U1---->ALF1
ACT1---->IS1
ALF1---->IS1
IS1--->D1
}
rectangle "External Directory Configuration" {
actor User as U2
database "External\nDirectory\n(e.g. LDAP)" as D2a
database "Configuration\nData\n(e.g. NoSQL)" as D2b
rectangle "Identity Service" as IS2
rectangle "Alfresco" as ALF2
rectangle "Activiti" as ACT2
U2---->ACT2
U2---->ALF2
ACT2---->IS2
ALF2---->IS2
IS2--->D2a
IS2--->D2b
}
rectangle "External Directory Configuration with SAML" {
actor User as U3
database "External\nDirectory\n(e.g. LDAP)" as D3a
database "Configuration\nData\n(e.g. NoSQL)" as D3b
rectangle "Identity Service" as IS3
rectangle "Alfresco" as ALF3
rectangle "Activiti" as ACT3
rectangle "SAML\nIdentity\nProvider" as IDP
U3---->ACT3
U3---->ALF3
ACT3---->IS3
ALF3---->IS3
IS3-->IDP
IDP-->D3a
IS3-->D3b
}
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,52 @@
@startuml
title Identity Data Model
sprite $primary [17x12/16z] bOqv3e1030CJRzPn9Fx_NWY7n4eqJ3TJs6OVa5pTpD-5tl3YyFHG-4DsqAOnWgawWp0r0KGagDuGMYMJxbMrBxzLPJ_O0G00
left to right direction
object Entity {
<$primary> id
name
email addresses
photo
other profile info
}
object Identity {
<$primary> id
}
object Group{
<$primary> id
name
}
object Domain {
<$primary> id
directoryType
directoryEndPoint
}
object Token {
<$primary> id
type
expirationTime
authority
}
object System {
<$primary> id
url
}
Group "1:n"----"0:n" Identity : members
Group "0:1"----"0:n" Group : members
Group "0:n"----"1:1" Domain : members
Identity "0:n"----"1:1" Domain : members
Identity "1:1"----"0:n" Token: granted
Domain "1:1"----"0:n" Token:issues
Identity "0:n"----"0:n" System : member
Identity "0:n"----"0:n" Entity : member
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -0,0 +1,51 @@
@startuml
@startuml
Title: Creating an Alfresco User
actor "End User\n <newuser>" as U
actor "Administrator\n" as A
participant "Admin Console" as AC
participant "API Gateway" as AG
participant "Identity Service" as IS
participant "User Topic" as UT
database "Directory\nNoSQL" as D
note left of U
The user created in this flow is an 'internal user', that is
one that is entirely managed by Alfresco Content Services
and not known to a Directory Service such as LDAP
end note
U->A: Request account via email
A->AC: create User
activate AC
AC->AG: HTTP POST /users/<newuser>
activate AG
note left of AG
public API
end note
AG->IS: HTTP POST ?identity service
note left of IS
internal API
end note
activate IS
IS->D: store the user account
activate D
D->IS: ok
deactivate D
IS->UT: AMQP POST userCreated message
activate UT
UT->IS: Message posted confirmation
deactivate UT
IS->AG: 201 created
deactivate IS
AG->AC: 201 created
deactivate AG
AC->A: user created\nconfirmation message
deactivate AC
A->U: Account created\nconfirmation email
@enduml
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -0,0 +1,152 @@
@startuml
Title: Interaction between Identity Service, Proxy, Activiti and Alfresco
participant "Browser" as B
participant "Identity Service" as IS
participant "Proxy" as P
participant "Alfresco Repository" as R
participant "Activiti" as A
== flow with Proxy ==
B->P: HTTP GET /something from Alfresco
activate B
activate P
note right of P
sees no authorization
header
end note
P->B: redirect
deactivate P
B->IS: authenticate
activate IS
B<-IS: login form
deactivate IS
note right of B
user enters
userid and
password
end note
note right of B
Assumption: common
password for Activiti
and Alfresco (such
as would be provided if
they shared an LDAP for
example (not pictured))
end note
B->IS: credentials
IS->R: credentials
activate R
R->R:checks credentials
R->R: generate alf_ticket
R->IS: alf_ticket
deactivate R
IS->IS: generate common_token
deactivate R
IS->IS:store common_token
IS->IS: store alf_ticket
note right of IS
common_token is
a key to retrieve
alf_ticket and
act_ticket
end note
IS->A: credentials
activate A
A->A:checks credentials
A->A: generate act_ticket
A->IS: act_ticket
deactivate A
IS->IS:store act_ticket
IS->B: redirect w/common_token
B->P: HTTP GET /something from Alfresco (with common_token)
activate P
note right of P
sees common_token in
authorization header
end note
P->IS:validate common_token and retrieve alf_ticket
activate IS
IS->P: alf_ticket
deactivate IS
P->R:HTTP GET /something (with alf_ticket)
R->R: validate alf_ticket
R->R: checks authorization of\nuser to something
R->P: something from Alfresco
deactivate R
P->B:something from Alfresco
deactivate P
B->P : HTTP GET something from Activiti (with common_token)
activate P
note right of P
sees common_token in
authorization header
end note
P->IS:validate common_token and retrieve act_ticket
activate IS
IS->P: act_ticket
deactivate IS
P->A:HTTP GET /something (with act_ticket)
A->A: validate act_ticket
A->A: checks authorization of\nuser to something
A->P: something from Activiti
deactivate A
P->B:something from Activiti
deactivate P
deactivate B
== flow without Proxy ==
B->R: HTTP GET /something from Alfresco
activate R
note right of R
sees no authorization
header
end note
R->B: redirect
deactivate R
B->IS: authenticate
activate IS
B<-IS: login form
deactivate IS
note right of B
user enters
userid and
password
end note
B->IS: credentials
IS->IS:checks credentials
IS->IS: generate common_token
IS->B:common_token
deactivate IS
B->R: HTTP GET /something from Alfresco (with common_token)
activate R
note right of R
sees common_token in
authorization header
end note
R->IS:validate common_token
activate IS
IS->R: OK
deactivate IS
R->R: checks authorization of\nuser to something
R->B: something from Alfresco
deactivate R
B->R: HTTP GET /something from Activiti (with common_token)
activate A
note right of A
sees common_token in
authorization header
end note
A->IS:validate common_token
activate IS
IS->A: OK
deactivate IS
A->A: checks authorization of\nuser to something
A->B: something from Activiti
deactivate A
deactivate B
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,110 @@
@startuml
@startuml
Title: OAuth Flow
actor "End User" as U
participant "Alfresco App" as ALF
participant "External System" as EXT
participant "OAuth Gateway Component" as OG
participant "API Gateway" as AG
participant "Identity Service" as IS
participant "User Topic" as UT
database "Directory\nNoSQL" as D
U->ALF: Login
activate U
ALF->AG: HTTP authn user (URL?)
activate AG
note right of AG
public API
end note
AG->IS: HTTP authn user (URL?)
note right of IS
internal API
end note
activate IS
IS->D: Retrieve user account
activate D
D->IS: Return user and validate creds
deactivate D
IS->UT: AMQP POST userLogin message
activate UT
UT->IS: Message posted confirmation
deactivate UT
IS->AG: Return token
deactivate IS
AG->ALF: Return token
deactivate AG
ALF->U: Render Page
deactivate U
U->ALF: Authorize external system
activate U
ALF->OG: Authorize external system
activate OG
OG->EXT: Redirect browser
activate EXT
EXT->U: External Login / App Auth Page
U->EXT: Login / Approve App
EXT->OG: Redirect w/ authz code
OG->EXT: Get OAuth tokens
EXT->OG: Return OAuth tokens
deactivate EXT
OG->AG: HTTP POST\n/users/{id}/identities/{extsysid}/tokens
activate AG
note right of AG
public API
end note
AG->IS: HTTP POST\n/users/{id}/identities/{extsysid}/tokens
note right of IS
internal API
end note
activate IS
IS->D: Store OAuth tokens
activate D
D->IS: ok
deactivate D
IS->UT: AMQP POST userTokenStored message
activate UT
UT->IS: Message posted confirmation
deactivate UT
IS->AG: 201 created
deactivate IS
AG->OG: 201 created
deactivate AG
OG->U: Success Page
deactivate OG
deactivate U
ALF->AG: HTTP GET\n/users/{id}/identities/{extsysid}/tokens
activate ALF
activate AG
note right of AG
public API
end note
AG->IS: HTTP GET\n/users/{id}/identities/{extsysid}/tokens
note right of IS
internal API
end note
activate IS
IS->D: Retrieve OAuth tokens
activate D
D->IS: Return OAuth tokens
deactivate D
IS->AG: Return OAuth tokens
deactivate IS
AG->ALF: Return OAuth tokens
deactivate AG
ALF->EXT: API call w/ OAuth tokens
activate EXT
EXT->ALF: Return external data
deactivate EXT
deactivate ALF
@enduml
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -0,0 +1,97 @@
@startuml
Title: Interaction between Identity Service and SAML
participant "SAML IdP" as S
participant "Identity Service" as IS
participant "Browser" as B
participant "Repository" as R
== flow without SAML ==
B->R: HTTP GET /something
activate B
activate R
note right of R
sees no authorization
header
end note
R->B: redirect
deactivate R
B->IS: authenticate
activate IS
B<-IS: login form
note right of B
user enters
userid and
password
end note
B->IS: credentials
IS->IS: check credentials
IS->B: redirect w/token
deactivate IS
B->R: HTTP GET /something (with token)
activate R
note right of R
sees token in
authorization header
end note
R->IS: validate token
activate IS
IS->R: OK
deactivate IS
R->R: extracts userid from token
R->R: checks authorization of\nuser to something
R->B: something
deactivate R
deactivate B
== flow with SAML ==
B->R: HTTP GET /something
activate B
activate R
note right of R
sees no authorization
header
end note
R->B: redirect
deactivate R
B->IS: authenticate
activate IS
IS->S: get assertion
deactivate IS
activate S
S->B: login form
deactivate S
note right of B
user enters
userid and
password
end note
S<-B: credentials
activate S
S<->S: check credentials
S->S: generate assertion
S->B: assertion w/redirect
deactivate S
B->IS:get token
activate IS
IS->IS: extract user from assertion
IS->IS: generate token
IS->B: redirect w/token
deactivate IS
B->R: HTTP GET /something (with token)
activate R
note right of R
sees token in
authorization header
end note
R->IS: validate token
IS->R: OK
R->R: extracts userid from token
R->R: checks authorization of\nuser to something
R->B: something
deactivate R
deactivate B
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

View File

@@ -0,0 +1,310 @@
@startuml
' Generated using https://github.com/juanmf/Java2PlantUML
left to right direction
' Participants
interface org.alfresco.repo.security.authentication.AlfrescoSecureContext {
--
+ getEffectiveAuthentication() : Authentication
+ getRealAuthentication() : Authentication
+ setEffectiveAuthentication(i Authentication) : void
+ setRealAuthentication(i Authentication) : void
}
interface net.sf.acegisecurity.context.security.SecureContext {
--
+ getAuthentication() : Authentication
+ setAuthentication(i Authentication) : void
}
class org.alfresco.repo.security.authentication.AuthenticationUtil$ThreadLocalStack {
--
~ AuthenticationUtil$ThreadLocalStack()
# initialValue() : Stack
}
class org.alfresco.repo.security.authentication.TicketExpiredException {
- serialVersionUID : long
--
+ TicketExpiredException(c String)
+ TicketExpiredException(c String, c Throwable)
}
class org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket {
- expires : c InMemoryTicketComponentImpl$ExpiryMode
- expiryDate : c Date
- serialVersionUID : long
- testDuration : c Duration
- ticketId : c String
- userName : c String
- validDuration : c Duration
--
- InMemoryTicketComponentImpl$Ticket(c InMemoryTicketComponentImpl$ExpiryMode, c Date, c String, c Duration, c String)
~ InMemoryTicketComponentImpl$Ticket(c InMemoryTicketComponentImpl$ExpiryMode, c Date, c String, c Duration)
# getExpires() : InMemoryTicketComponentImpl$ExpiryMode
# getExpiryDate() : Date
# getTicketId() : String
# getUserName() : String
+ equals(c Object) : boolean
+ hashCode() : int
~ getNewEntry() : InMemoryTicketComponentImpl$Ticket
~ hasExpired(c Date) : boolean
}
class org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl {
+ GRANTED_AUTHORITY_TICKET_PREFIX : c String
- currentTicket : ThreadLocal< String>
- expiryMode : c InMemoryTicketComponentImpl$ExpiryMode
- guid : c String
- oneOff : boolean
- ticketsCache : SimpleCache< String, InMemoryTicketComponentImpl$Ticket>
- ticketsExpire : boolean
- useSingleTicketPerUser : boolean
- validDuration : c Duration
--
+ InMemoryTicketComponentImpl()
+ clearCurrentSecurityContext() : void
+ clearCurrentTicket() : void
+ countTickets(boolean) : int
+ equals(c Object) : boolean
+ getAuthorityForTicket(c String) : String
+ getCurrentTicket(c String, boolean) : String
+ getNewTicket(c String) : String
+ getUseSingleTicketPerUser() : boolean
+ getUsersWithTickets(boolean) : Set
+ hashCode() : int
+ invalidateTicketById(c String) : void
+ invalidateTicketByUser(c String) : void
+ invalidateTickets(boolean) : int
+ setExpiryMode(c String) : void
+ setOneOff(boolean) : void
+ setTicketsCache( SimpleCache< String, InMemoryTicketComponentImpl$Ticket>) : void
+ setTicketsExpire(boolean) : void
+ setUseSingleTicketPerUser(boolean) : void
+ setValidDuration(c String) : void
+ validateTicket(c String) : String
- findNonExpiredUserTicket(c String) : InMemoryTicketComponentImpl$Ticket
- getTicketByTicketString(c String) : InMemoryTicketComponentImpl$Ticket
- getTicketKey(c String) : String
}
interface org.springframework.beans.factory.InitializingBean {
--
+ afterPropertiesSet() : void
}
interface org.alfresco.repo.security.authentication.AuthenticationStep {
--
+ getArgs() : Object;
+ getKey() : String
+ getMessage() : String
+ isSuccess() : boolean
}
interface org.alfresco.repo.security.authentication.AuthenticationUtil$RunAsWork <Result extends c Object> {
--
+ doWork() : Object
}
class org.alfresco.repo.security.authentication.AuthenticationUtil {
+ SYSTEM_USER_NAME : c String
- defaultAdminUserName : c String
- defaultGuestUserName : c String
- initialized : boolean
- mtEnabled : boolean
- threadLocalFullAuthenticationStack : ThreadLocal< Stack< Authentication>>
- threadLocalRunAsAuthenticationStack : ThreadLocal< Stack< Authentication>>
- threadLocalTenantDomainStack : ThreadLocal< Stack< String>>
~ s_logger : i Log
--
+ AuthenticationUtil()
+ afterPropertiesSet() : void
+ clearCurrentSecurityContext() : void
+ getAdminRoleName() : String
+ getAdminUserName() : String
+ getFullAuthentication() : Authentication
+ getFullyAuthenticatedUser() : String
+ getGuestRoleName() : String
+ getGuestUserName() : String
+ getRunAsAuthentication() : Authentication
+ getRunAsUser() : String
+ getSystemUserName() : String
+ getUserTenant(c String) : Pair
+ isMtEnabled() : boolean
+ isRunAsUserTheSystemUser() : boolean
+ logAuthenticatedUsers() : void
+ logNDC(c String) : void
+ popAuthentication() : void
+ pushAuthentication() : void
+ runAs( AuthenticationUtil$RunAsWork<R>, c String) : Object
+ runAsSystem( AuthenticationUtil$RunAsWork<R>) : Object
+ setAdminUserAsFullyAuthenticatedUser() : Authentication
+ setDefaultAdminUserName(c String) : void
+ setDefaultGuestUserName(c String) : void
+ setFullAuthentication(i Authentication) : Authentication
+ setFullyAuthenticatedUser(c String) : Authentication
+ setMtEnabled(boolean) : void
+ setRunAsUser(c String) : Authentication
+ setRunAsUserSystem() : Authentication
- getAuthenticationToken(c String, i UserDetails) : UsernamePasswordAuthenticationToken
- getDefaultUserDetails(c String) : UserDetails
- getUserName(i Authentication) : String
- setFullyAuthenticatedUser(c String, i UserDetails) : Authentication
~ setRunAsAuthentication(i Authentication) : Authentication
~ setRunAsUser(c String, i UserDetails) : Authentication
}
class org.alfresco.repo.security.authentication.AuthenticationException {
- serialVersionUID : long
~ diagnostic : c AuthenticationDiagnostic
--
+ AuthenticationException(c String)
+ AuthenticationException(c String, c AuthenticationDiagnostic)
+ AuthenticationException(c String, c AuthenticationDiagnostic, c Object;, c Throwable)
+ AuthenticationException(c String, c AuthenticationDiagnostic, c Throwable)
+ AuthenticationException(c String, c Object;)
+ AuthenticationException(c String, c Object;, c AuthenticationDiagnostic)
+ AuthenticationException(c String, c Object;, c Throwable)
+ AuthenticationException(c String, c Throwable)
+ getDiagnostic() : AuthenticationDiagnostic
}
class org.alfresco.error.AlfrescoRuntimeException {
- MESSAGE_DELIMITER : c String
- errorCounter : c AtomicInteger
- msgId : c String
- msgParams : c Object;
- serialVersionUID : long
--
+ AlfrescoRuntimeException(c String)
+ AlfrescoRuntimeException(c String, c Object;)
+ AlfrescoRuntimeException(c String, c Object;, c Throwable)
+ AlfrescoRuntimeException(c String, c Throwable)
+ create(c String, c Object;) : AlfrescoRuntimeException
+ create(c Throwable, c String, c Object;) : AlfrescoRuntimeException
+ getMsgId() : String
+ getMsgParams() : Object;
+ getNumericalId() : String
+ getRootCause() : Throwable
+ makeRuntimeException(c Throwable, c String, c Object;) : RuntimeException
- buildErrorLogNumber(c String) : String
- padInt(c StringBuilder, int, int) : void
- resolveMessage(c String, c Object;) : String
}
class org.alfresco.repo.security.authentication.AuthenticationDiagnostic {
+ STEP_KEY_LDAP_AUTHENTICATION : c String
+ STEP_KEY_LDAP_CONNECTED : c String
+ STEP_KEY_LDAP_CONNECTING : c String
+ STEP_KEY_LDAP_FORMAT_USER : c String
+ STEP_KEY_LDAP_LOOKEDUP_USER : c String
+ STEP_KEY_LDAP_LOOKUP_USER : c String
+ STEP_KEY_LDAP_SEARCH : c String
+ STEP_KEY_VALIDATION : c String
+ STEP_KEY_VALIDATION_AUTHENTICATOR_NOT_ACTIVE : c String
+ STEP_KEY_VALIDATION_AUTHENTICATOR_NOT_FOUND : c String
- serialVersionUID : long
- steps : List< AuthenticationStep>
--
+ AuthenticationDiagnostic()
+ addStep(c String, boolean) : void
+ addStep(c String, boolean, c Object;) : void
+ addStep(i AuthenticationStep) : void
+ getSteps() : List
}
class org.alfresco.repo.security.authentication.AuthenticationStepImpl {
- serialVersionUID : long
~ args : c Object;
~ key : c String
~ success : boolean
--
+ AuthenticationStepImpl(c String)
+ getArgs() : Object;
+ getKey() : String
+ getMessage() : String
+ isSuccess() : boolean
+ toString() : String
}
interface net.sf.acegisecurity.context.Context {
--
+ validate() : void
}
class org.alfresco.repo.security.authentication.AlfrescoSecureContextImpl {
- effectiveAuthentication : i Authentication
- realAuthentication : i Authentication
- serialVersionUID : long
--
+ AlfrescoSecureContextImpl()
+ equals(c Object) : boolean
+ getAuthentication() : Authentication
+ getEffectiveAuthentication() : Authentication
+ getRealAuthentication() : Authentication
+ hashCode() : int
+ setAuthentication(i Authentication) : void
+ setEffectiveAuthentication(i Authentication) : void
+ setRealAuthentication(i Authentication) : void
+ toString() : String
+ validate() : void
}
enum org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$ExpiryMode {
+ AFTER_FIXED_TIME : c InMemoryTicketComponentImpl$ExpiryMode
+ AFTER_INACTIVITY : c InMemoryTicketComponentImpl$ExpiryMode
+ DO_NOT_EXPIRE : c InMemoryTicketComponentImpl$ExpiryMode
--
- InMemoryTicketComponentImpl$ExpiryMode()
+ valueOf(c String) : InMemoryTicketComponentImpl$ExpiryMode
+ values() : InMemoryTicketComponentImpl$ExpiryMode;
}
interface org.alfresco.repo.security.authentication.TicketComponent {
--
+ clearCurrentTicket() : void
+ countTickets(boolean) : int
+ getAuthorityForTicket(c String) : String
+ getCurrentTicket(c String, boolean) : String
+ getNewTicket(c String) : String
+ getUseSingleTicketPerUser() : boolean
+ getUsersWithTickets(boolean) : Set
+ invalidateTicketById(c String) : void
+ invalidateTicketByUser(c String) : void
+ invalidateTickets(boolean) : int
+ validateTicket(c String) : String
}
' Relations
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl "1" o-left- "1" org.alfresco.repo.cache.SimpleCache : ticketsCache: SimpleCache< String, InMemoryTicketComponentImpl$Ticket>
org.alfresco.repo.security.authentication.AlfrescoSecureContextImpl "1" o-left- "1" net.sf.acegisecurity.Authentication : realAuthentication: i Authentication
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket "1" o-left- "1" org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$ExpiryMode : expires: c InMemoryTicketComponentImpl$ExpiryMode
org.alfresco.error.AlfrescoRuntimeException "1" o-left- "1" java.util.concurrent.atomic.AtomicInteger : errorCounter: c AtomicInteger
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket "1" o-left- "1" org.alfresco.service.cmr.repository.datatype.Duration : testDuration: c Duration
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket "1" o-left- "1" org.alfresco.service.cmr.repository.datatype.Duration : validDuration: c Duration
org.alfresco.repo.security.authentication.AuthenticationUtil "1" o-left- "1" org.apache.commons.logging.Log : s_logger: i Log
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl "1" o-left- "1" org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$ExpiryMode : expiryMode: c InMemoryTicketComponentImpl$ExpiryMode
org.alfresco.repo.security.authentication.AuthenticationException "1" o-left- "1" org.alfresco.repo.security.authentication.AuthenticationDiagnostic : diagnostic: c AuthenticationDiagnostic
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket "1" o-left- "1" java.util.Date : expiryDate: c Date
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl "1" o-left- "1" org.alfresco.service.cmr.repository.datatype.Duration : validDuration: c Duration
org.alfresco.repo.security.authentication.AlfrescoSecureContextImpl "1" o-left- "1" net.sf.acegisecurity.Authentication : effectiveAuthentication: i Authentication
org.alfresco.repo.security.authentication.AuthenticationException -up|> org.alfresco.error.AlfrescoRuntimeException
org.alfresco.repo.security.authentication.TicketExpiredException -up|> org.alfresco.repo.security.authentication.AuthenticationException
"net.sf.acegisecurity.context.Context" -() Serializable
"org.alfresco.repo.security.authentication.AuthenticationStepImpl" -() Serializable
org.alfresco.repo.security.authentication.AlfrescoSecureContext ..up|> net.sf.acegisecurity.context.security.SecureContext
org.alfresco.repo.security.authentication.AuthenticationStepImpl ..up|> org.alfresco.repo.security.authentication.AuthenticationStep
org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl ..up|> org.alfresco.repo.security.authentication.TicketComponent
net.sf.acegisecurity.context.security.SecureContext ..up|> net.sf.acegisecurity.context.Context
"org.alfresco.repo.security.authentication.AuthenticationDiagnostic" -() Serializable
"org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl$Ticket" -() Serializable
org.alfresco.repo.security.authentication.AlfrescoSecureContextImpl ..up|> org.alfresco.repo.security.authentication.AlfrescoSecureContext
org.alfresco.repo.security.authentication.AuthenticationUtil ..up|> org.springframework.beans.factory.InitializingBean
' Notes
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 KiB

View File

@@ -0,0 +1,344 @@
@startuml
left to right direction
' Generated using https://github.com/juanmf/Java2PlantUML
' Participants
class org.alfresco.error.AlfrescoRuntimeException {
- MESSAGE_DELIMITER : c String
- errorCounter : c AtomicInteger
- msgId : c String
- msgParams : c Object;
- serialVersionUID : long
--
+ AlfrescoRuntimeException(c String)
+ AlfrescoRuntimeException(c String, c Object;)
+ AlfrescoRuntimeException(c String, c Object;, c Throwable)
+ AlfrescoRuntimeException(c String, c Throwable)
+ create(c String, c Object;) : AlfrescoRuntimeException
+ create(c Throwable, c String, c Object;) : AlfrescoRuntimeException
+ getMsgId() : String
+ getMsgParams() : Object;
+ getNumericalId() : String
+ getRootCause() : Throwable
+ makeRuntimeException(c Throwable, c String, c Object;) : RuntimeException
- buildErrorLogNumber(c String) : String
- padInt(c StringBuilder, int, int) : void
- resolveMessage(c String, c Object;) : String
}
class org.alfresco.service.cmr.security.NoSuchPersonException {
- serialVersionUID : long
- userName : c String
--
+ NoSuchPersonException(c String)
+ getUserName() : String
}
interface org.alfresco.service.cmr.security.OwnableService {
+ NO_OWNER : c String
--
+ getOwner(c NodeRef) : String
+ hasOwner(c NodeRef) : boolean
+ setOwner(c NodeRef, c String) : void
+ takeOwnership(c NodeRef) : void
}
class org.alfresco.service.cmr.security.PersonService$PersonInfo {
- firstName : c String
- lastName : c String
- nodeRef : c NodeRef
- userName : c String
--
+ PersonService$PersonInfo(c NodeRef, c String, c String, c String)
+ getFirstName() : String
+ getLastName() : String
+ getNodeRef() : NodeRef
+ getUserName() : String
}
enum org.alfresco.service.cmr.security.AccessStatus {
+ ALLOWED : c AccessStatus
+ DENIED : c AccessStatus
+ UNDETERMINED : c AccessStatus
--
- AccessStatus()
+ valueOf(c String) : AccessStatus
+ values() : AccessStatus;
}
interface org.alfresco.service.cmr.security.AuthenticationService {
--
+ authenticate(c String, class [C) : void
+ authenticateAsGuest() : void
+ authenticationExists(c String) : boolean
+ clearCurrentSecurityContext() : void
+ getAuthenticationEnabled(c String) : boolean
+ getCurrentTicket() : String
+ getCurrentUserName() : String
+ getDefaultAdministratorUserNames() : Set
+ getDefaultGuestUserNames() : Set
+ getDomains() : Set
+ getDomainsThatAllowUserCreation() : Set
+ getDomainsThatAllowUserDeletion() : Set
+ getDomiansThatAllowUserPasswordChanges() : Set
+ getNewTicket() : String
+ guestUserAuthenticationAllowed() : boolean
+ invalidateTicket(c String) : void
+ invalidateUserSession(c String) : void
+ isCurrentUserTheSystemUser() : boolean
+ validate(c String) : void
}
interface org.alfresco.service.cmr.security.AuthorityService {
+ ZONE_APP_DEFAULT : c String
+ ZONE_APP_SHARE : c String
+ ZONE_AUTH_ALFRESCO : c String
+ ZONE_AUTH_EXT_PREFIX : c String
--
+ addAuthority( Collection< String>, c String) : void
+ addAuthority(c String, c String) : void
+ addAuthorityToZones(c String, Set< String>) : void
+ authorityExists(c String) : boolean
+ countGroups() : long
+ countUsers() : long
+ createAuthority(c AuthorityType, c String) : String
+ createAuthority(c AuthorityType, c String, c String, Set< String>) : String
+ deleteAuthority(c String) : void
+ deleteAuthority(c String, boolean) : void
+ findAuthorities(c AuthorityType, c String, boolean, c String, c String) : Set
+ getAllAuthorities(c AuthorityType) : Set
+ getAllAuthoritiesInZone(c String, c AuthorityType) : Set
+ getAllRootAuthorities(c AuthorityType) : Set
+ getAllRootAuthoritiesInZone(c String, c AuthorityType) : Set
+ getAuthorities() : Set
+ getAuthorities(c AuthorityType, c String, c String, boolean, boolean, c PagingRequest) : PagingResults
+ getAuthoritiesForUser(c String) : Set
+ getAuthoritiesInfo(c AuthorityType, c String, c String, c String, boolean, c PagingRequest) : PagingResults
+ getAuthorityDisplayName(c String) : String
+ getAuthorityNodeRef(c String) : NodeRef
+ getAuthorityZones(c String) : Set
+ getContainedAuthorities(c AuthorityType, c String, boolean) : Set
+ getContainingAuthorities(c AuthorityType, c String, boolean) : Set
+ getContainingAuthoritiesInZone(c AuthorityType, c String, c String, i AuthorityService$AuthorityFilter, int) : Set
+ getDefaultZones() : Set
+ getName(c AuthorityType, c String) : String
+ getOrCreateZone(c String) : NodeRef
+ getShortName(c String) : String
+ getZone(c String) : NodeRef
+ hasAdminAuthority() : boolean
+ hasGuestAuthority() : boolean
+ isAdminAuthority(c String) : boolean
+ isGuestAuthority(c String) : boolean
+ removeAuthority(c String, c String) : void
+ removeAuthorityFromZones(c String, Set< String>) : void
+ setAuthorityDisplayName(c String, c String) : void
}
enum org.alfresco.service.cmr.security.AuthorityType {
+ ADMIN : c AuthorityType
+ EVERYONE : c AuthorityType
+ GROUP : c AuthorityType
+ GUEST : c AuthorityType
+ OWNER : c AuthorityType
+ ROLE : c AuthorityType
+ USER : c AuthorityType
+ WILDCARD : c AuthorityType
--
- AuthorityType()
+ equals(c String) : boolean
+ getAuthorityType(c String) : AuthorityType
+ getFixedString() : String
+ getOrderPosition() : int
+ getPrefixString() : String
+ isFixedString() : boolean
+ isPrefixed() : boolean
+ valueOf(c String) : AuthorityType
+ values() : AuthorityType;
}
interface org.alfresco.service.cmr.security.PersonService {
--
+ countPeople() : int
+ createMissingPeople() : boolean
+ createPerson( Map< QName, Serializable>) : NodeRef
+ createPerson( Map< QName, Serializable>, Set< String>) : NodeRef
+ deletePerson(c NodeRef) : void
+ deletePerson(c NodeRef, boolean) : void
+ deletePerson(c String) : void
+ getAllPeople() : Set
+ getMutableProperties() : Set
+ getPeople( List< Pair< QName, String>>, boolean, List< Pair< QName, Boolean>>, c PagingRequest) : PagingResults
+ getPeople(c String, List< QName>, List< Pair< QName, Boolean>>, c PagingRequest) : PagingResults
+ getPeople(c String, List< QName>, Set< QName>, Set< QName>, boolean, List< Pair< QName, Boolean>>, c PagingRequest) : PagingResults
+ getPeopleContainer() : NodeRef
+ getPeopleFilteredByProperty(c QName, i Serializable, int) : Set
+ getPerson(c NodeRef) : PersonService$PersonInfo
+ getPerson(c String) : NodeRef
+ getPerson(c String, boolean) : NodeRef
+ getPersonOrNull(c String) : NodeRef
+ getUserIdentifier(c String) : String
+ getUserNamesAreCaseSensitive() : boolean
+ isEnabled(c String) : boolean
+ isMutable() : boolean
+ notifyPerson(c String, c String) : void
+ personExists(c String) : boolean
+ setCreateMissingPeople(boolean) : void
+ setPersonProperties(c String, Map< QName, Serializable>) : void
+ setPersonProperties(c String, Map< QName, Serializable>, boolean) : void
}
interface org.alfresco.service.cmr.security.PublicServiceAccessService {
--
+ hasAccess(c String, c String, c Object;) : AccessStatus
}
interface org.alfresco.service.cmr.security.MutableAuthenticationService {
--
+ createAuthentication(c String, class [C) : void
+ deleteAuthentication(c String) : void
+ isAuthenticationCreationAllowed() : boolean
+ isAuthenticationMutable(c String) : boolean
+ setAuthentication(c String, class [C) : void
+ setAuthenticationEnabled(c String, boolean) : void
+ updateAuthentication(c String, class [C, class [C) : void
}
class org.alfresco.service.cmr.security.PermissionContext {
- additionalContext : Map< String, Object>
- aspects : HashSet< QName>
- dynamicAuthorityAssignment : Map< String, Set< String>>
- properties : Map< QName, Serializable>
- storeAcl : c Long
- type : c QName
--
+ PermissionContext(c QName)
+ addDynamicAuthorityAssignment(c String, c String) : void
+ getAdditionalContext() : Map
+ getAspects() : HashSet
+ getDynamicAuthorityAssignment() : Map
+ getProperties() : Map
+ getStoreAcl() : Long
+ getType() : QName
+ setStoreAcl(c Long) : void
}
interface org.alfresco.repo.security.permissions.PermissionCheckValue {
--
+ getNodeRef() : NodeRef
}
interface org.alfresco.service.cmr.security.PermissionService {
+ ADD_CHILDREN : c String
+ ADMINISTRATOR_AUTHORITY : c String
+ ALL_AUTHORITIES : c String
+ ALL_PERMISSIONS : c String
+ ASPECTS : c String
+ CANCEL_CHECK_OUT : c String
+ CHANGE_PERMISSIONS : c String
+ CHECK_IN : c String
+ CHECK_OUT : c String
+ CONSUMER : c String
+ CONTRIBUTOR : c String
+ COORDINATOR : c String
+ CREATE_ASSOCIATIONS : c String
+ CREATE_CHILDREN : c String
+ DELETE : c String
+ DELETE_ASSOCIATIONS : c String
+ DELETE_CHILDREN : c String
+ DELETE_NODE : c String
+ EDITOR : c String
+ EXECUTE : c String
+ EXECUTE_CONTENT : c String
+ FULL_CONTROL : c String
+ GROUP_PREFIX : c String
+ GUEST_AUTHORITY : c String
+ LINK_CHILDREN : c String
+ LOCK : c String
+ LOCK_OWNER_AUTHORITY : c String
+ OWNER_AUTHORITY : c String
+ PROPERTIES : c String
+ READ : c String
+ READ_ASSOCIATIONS : c String
+ READ_CHILDREN : c String
+ READ_CONTENT : c String
+ READ_PERMISSIONS : c String
+ READ_PROPERTIES : c String
+ ROLE_PREFIX : c String
+ SET_OWNER : c String
+ TAKE_OWNERSHIP : c String
+ UNLOCK : c String
+ WRITE : c String
+ WRITE_CONTENT : c String
+ WRITE_PROPERTIES : c String
--
+ clearPermission(c NodeRef, c String) : void
+ clearPermission(c StoreRef, c String) : void
+ deletePermission(c NodeRef, c String, c String) : void
+ deletePermission(c StoreRef, c String, c String) : void
+ deletePermissions(c NodeRef) : void
+ deletePermissions(c StoreRef) : void
+ getAllAuthorities() : String
+ getAllPermission() : String
+ getAllSetPermissions(c NodeRef) : Set
+ getAllSetPermissions(c StoreRef) : Set
+ getAuthorisations() : Set
+ getInheritParentPermissions(c NodeRef) : boolean
+ getOwnerAuthority() : String
+ getPermissions(c NodeRef) : Set
+ getReaders(c Long) : Set
+ getReadersDenied(c Long) : Set
+ getSettablePermissions(c NodeRef) : Set
+ getSettablePermissions(c QName) : Set
+ hasPermission(c Long, c PermissionContext, c String) : AccessStatus
+ hasPermission(c NodeRef, c String) : AccessStatus
+ hasReadPermission(c NodeRef) : AccessStatus
+ setInheritParentPermissions(c NodeRef, boolean) : void
+ setInheritParentPermissions(c NodeRef, boolean, boolean) : void
+ setPermission(c NodeRef, c String, c String, boolean) : void
+ setPermission(c StoreRef, c String, c String, boolean) : void
}
interface org.alfresco.service.cmr.security.AuthorityService$AuthorityFilter {
--
+ includeAuthority(c String) : boolean
}
interface org.alfresco.service.cmr.security.AccessPermission {
--
+ getAccessStatus() : AccessStatus
+ getAuthority() : String
+ getAuthorityType() : AuthorityType
+ getPermission() : String
+ getPosition() : int
+ isInherited() : boolean
+ isSetDirectly() : boolean
}
class org.alfresco.repo.security.person.PersonException {
- serialVersionUID : long
--
+ PersonException(c String)
+ PersonException(c String, c Object;)
+ PersonException(c String, c Object;, c Throwable)
+ PersonException(c String, c Throwable)
}
' Relations
org.alfresco.service.cmr.security.PersonService$PersonInfo "1" o-left- "1" org.alfresco.service.cmr.repository.NodeRef : nodeRef: c NodeRef
org.alfresco.error.AlfrescoRuntimeException "1" o-left- "1" java.util.concurrent.atomic.AtomicInteger : errorCounter: c AtomicInteger
org.alfresco.service.cmr.security.PermissionContext "1" o-left- "*" org.alfresco.service.namespace.QName : aspects: HashSet< QName>
org.alfresco.service.cmr.security.PermissionContext "1" o-left- "1" org.alfresco.service.namespace.QName : type: c QName
org.alfresco.service.cmr.security.PermissionContext "1" o-left- "*" org.alfresco.service.namespace.QName : properties: Map< QName, Serializable>
org.alfresco.repo.security.person.PersonException -up|> org.alfresco.error.AlfrescoRuntimeException
org.alfresco.service.cmr.security.NoSuchPersonException -up|> org.alfresco.repo.security.person.PersonException
org.alfresco.service.cmr.security.MutableAuthenticationService ..up|> org.alfresco.service.cmr.security.AuthenticationService
org.alfresco.service.cmr.security.PersonService$PersonInfo ..up|> org.alfresco.repo.security.permissions.PermissionCheckValue
' Notes
@enduml

View File

@@ -0,0 +1,8 @@
# Repository -> Infrastructure
## Sub-components
* [ ] [Module Framework](./module-framework)
* [ ] [Cluster](./cluster)
* [ ] [Policies and Behaviours](./policies-and-behaviours)
* [ ] [Multi-tenancy](./multi-tenancy)

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,30 @@
@startuml
title Tenant Service (aws)
interface TenantService
interface TenantServiceSPI
class Tenant
class TenantServiceDDBImpl
class TenantServiceImpl
class TenantServiceLambda
Tenant <.. TenantService : uses
Tenant <.. TenantServiceDDBImpl : uses
Tenant <.. TenantServiceImpl : uses
Tenant <.. TenantServiceSPI : uses
TenantServiceDDBImpl <.. TenantServiceLambda : uses
TenantServiceImpl <.. TenantServiceLambda : uses
TenantServiceSPI <.. TenantServiceImpl : uses
TenantServiceSPI <.. TenantServiceLambda : uses
TenantService <|.. TenantServiceImpl : implements
TenantServiceSPI <|.. TenantServiceDDBImpl : implements
center footer © 2016 Alfresco Software Inc. all rights reserved \n Generated from PlantUML
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -0,0 +1,89 @@
@startuml
left to right direction
interface com.alfresco.services.lambda.TenantServiceSPI {
--
+ createTenant(c String, c String) : Tenant
+ deleteTenant(c String) : boolean
+ getTenant(c String) : Tenant
+ getTenantSchema(c String) : String
+ updateTenant(c Tenant) : boolean
}
interface com.alfresco.services.lambda.TenantService {
--
+ createTenant(c String, c String) : Tenant
+ deleteTenant(c String) : boolean
+ getTenant(c String) : Tenant
+ getTenantSchema(c String) : String
+ updateTenant(c Tenant) : boolean
}
class com.alfresco.services.lambda.TenantServiceDDBImpl {
- regions : c Regions
- tableName : c String
--
+ TenantServiceDDBImpl()
+ createTenant(c String, c String) : Tenant
+ deleteTenant(c String) : boolean
+ getTenant(c String) : Tenant
+ getTenantSchema(c String) : String
+ updateTenant(c Tenant) : boolean
- log(c String) : void
}
class com.alfresco.services.lambda.TenantServiceLambda {
--
+ TenantServiceLambda()
+ handleRequest(c Tenant, i Context) : Tenant
}
class com.alfresco.services.lambda.TenantServiceImpl {
- tenantServiceSPI : i TenantServiceSPI
--
+ TenantServiceImpl(i TenantServiceSPI)
+ createTenant(c String, c String) : Tenant
+ deleteTenant(c String) : boolean
+ getTenant(c String) : Tenant
+ getTenantSchema(c String) : String
+ updateTenant(c Tenant) : boolean
}
class com.alfresco.services.lambda.Tenant {
- method : c String
- schema : c String
- spiProvider : c String
- tenantId : c String
- user : c String
--
+ Tenant()
+ getMethod() : String
+ getSchema() : String
+ getSpiProvider() : String
+ getTenantId() : String
+ getUser() : String
+ setMethod(c String) : void
+ setSchema(c String) : void
+ setSpiProvider(c String) : void
+ setTenantId(c String) : void
+ setUser(c String) : void
}
interface com.amazonaws.services.lambda.runtime.RequestHandler <I extends c Object, O extends c Object> {
--
+ handleRequest(I, i Context) : Object
}
' Relations
com.alfresco.services.lambda.TenantServiceImpl "1" o-left- "1" com.alfresco.services.lambda.TenantServiceSPI : tenantServiceSPI: i TenantServiceSPI
com.alfresco.services.lambda.TenantServiceDDBImpl "1" o-left- "1" com.amazonaws.regions.Regions : regions: c Regions
com.alfresco.services.lambda.TenantServiceImpl ..up|> com.alfresco.services.lambda.TenantService
com.alfresco.services.lambda.TenantServiceDDBImpl ..up|> com.alfresco.services.lambda.TenantServiceSPI
com.alfresco.services.lambda.TenantServiceLambda ..up|> com.amazonaws.services.lambda.runtime.RequestHandler
' Notes
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,51 @@
@startuml
title Tenant Component (nosql)
skinparam linetype ortho
interface ApiConstants
interface TenantService
interface TenantServiceSPI
class AbstractRestResource {
#switchTenant()
}
class AbstractServiceClient
class An2ApiException
class CreateTenantPojo
class Cx1TenantService
class GetTenantPojo
class InitializingBean
class NoSuchTenantException
class TenantExistsException
class TenantService
class TenantServiceClient
class TenantServiceImpl
class TenantServiceIT
class TenantServiceRestV1
class VersionCheckException
AbstractRestResource <|-- TenantServiceRestV1 : extends
AbstractServiceClient <|-- TenantServiceClient : extends
An2ApiException <|-- NoSuchTenantException : extends
An2ApiException <|-- TenantExistsException : extends
An2ApiException <|-- VersionCheckException : extends
ApiConstants <|.. TenantServiceImpl : uses
CreateTenantPojo <.. TenantServiceClient : uses
CreateTenantPojo <.. TenantServiceRestV1 : uses
GetTenantPojo <.. TenantServiceClient : uses
GetTenantPojo <.. TenantServiceRestV1 : uses
InitializingBean <|.. TenantServiceImpl : implements
NoSuchTenantException <.. AbstractRestResource : uses
TenantService <.. AbstractRestResource : uses
TenantService <|.. TenantServiceClient : implements
TenantService <|.. TenantServiceImpl : implements
TenantService <|.. TenantServiceRestV1 : uses
TenantServiceClient <.. TenantServiceIT : uses
TenantServiceSPI <.. Cx1TenantService : implements
TenantServiceSPI <.. TenantServiceImpl : uses
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,39 @@
@startuml
title Tenant Service (nosql)
skinparam linetype ortho
node "Service\nClient" as SC #E0F2F1
node "API Gateway" as APIG #EEEEEE {
node "/tenants Resource" as TR #EFEBE9 {
node "method POST" as POST #FBE9E7 {
node "POST \nbody mapping template" #DCEDC8
}
node "method PUT" as PUT #FBE9E7{
node "PUT \nbody mapping template" #DCEDC8
}
node "method GET" as GET #FBE9E7
node "method DELETE" As DELETE #FBE9E7
}
}
node "Tenant Service \nLambda Function" as L #FFD54F
database "DynamoDB Database\nalf-data-tenants" as DB #80D8FF
node "DynamoDB\nClient" As DDBC #B3E5FC
node "DynamoDB" As DDB #B2EBF2
SC->TR:https
POST->L:JSON
PUT->L:JSON
GET->L:URL {tenant-id}
DELETE->L:URL {tenant-id}
L->DDBC
DDBC->DDB:reads/writes
DDB->DB:reads/writes
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -0,0 +1,86 @@
@startuml
Title Tenant Deployment\nDesign Options
skinparam nodeBorderColor black
left to right direction
node "AWS" as 2G #EEEEEE {
node "Tenant\nService" as 2T #white
node "Alfresco\nControl Architecture" as 2CA #white
node "Customer A" as 2C1 #FFCDD2 {
node "Alfresco 5.1" as 2A1 #E6EE9C {
node "Tenant" as 2T1
}
}
node "Customer B" as 2C2 #FFCDD2{
node "Alfresco 5.1" as 2A2 #E6EE9C {
node "Tenant" as 2T2
}
}
node "Customer C" as 2C3 #FFCDD2{
node "Alfresco 5.1" as 2A3 #E6EE9C {
node "Tenant" as 2T3
}
}
node "Customers D and E" as CDE #FFCDD2{
node "Repository Next" as 2B #B3E5FC
node "Tenant\n(Customer D)" as 2CD
node "Tenant\n(Customer E)" as 2CE
}
}
2CA=>2C1
2CA=>2C2
2CA=>2C3
2CA=>CDE
2CA=>2T
2T=>2CD
2T=>2CE
2B=>2T
node "AWS" as G #EEEEEE {
node "Alfresco\nControl Architecture" as CA #white
node "Customer A" as C1 #FFCDD2 {
node "Alfresco 5.1" as A1 #E6EE9C {
node "Tenant" as T1
}
}
node "Customer B" as C2 #FFCDD2{
node "Alfresco 5.1" as A2 #E6EE9C {
node "Tenant" as T2
}
}
node "Customer C" as C3 #FFCDD2{
node "Alfresco 5.1" as A3 #E6EE9C {
node "Tenant" as T3
}
}
node "Customer D" as C4 #FFCDD2 {
node "Tenant\nService" as TC1 #white
node "Tenant" as T5
node "Repository Next" as B1 #B3E5FC
}
node "Customer E" as C5 #FFCDD2 {
node "Tenant\nService" as TC2 #white
node "Tenant" as T6
node "Tenant" as T7
node "Tenant" as T8
node "Repository Next" as B2 #B3E5FC
}
}
TC1=>T5
TC2=>T6
TC2=>T7
TC2=>T8
CA=>C1
CA=>C2
CA=>C3
CA=>C4
CA=>C5
B2=>TC2
B1=>TC1
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@@ -0,0 +1,69 @@
@startuml
Title: Create a Tenant (NoSQL - AWS)
actor "User" as U
participant "Tenant Console" as TC
participant "API Gateway" as APIG
participant "TenantServiceLambda" as TSL
participant "TenantServiceImpl" as TSI
participant "DDbTenantService" as DDTS
participant "Dynamo DB Client" as DDBC
database "DynamoDB" as DDB
U->TC:create Tenant
note right
What the Tenant Console
is is TBD. It
may be part of the
AWS Control Architecture
or a Beowulf Admin
Console
end note
activate TC
TC->APIG: HTTP POST {<API Gateway host:port>/public/an2/v1/tenants\nTenant Object(JSON)
activate APIG
APIG->TSL: handler(serialized Tenant Object(JSON))
note right
The HTTP Verb and UserInfo is
passed to the Tenant Service
Lambda in the JSON object.
Tenant Service Lambda selects
the TenantServiceImpl method
to call based on the HTTP Verb
end note
activate TSL
TSL->TSI: createTenant()
note right
Unsolved Design Challenge #1:
How to supply a configuration
to allow alternative
implementations at
runtime. In current
form, the TenantServiceSPI
passed to TenantServiceImpl
is set in an API Gateway
template. That would allow
us to specify a different
provider of the SPI using,
for example, an HTTP parm
end note
activate TSI
TSI->DDTS
activate DDTS
DDTS->DDBC: table.putItem(new Item().withPrimaryKey("tenant-id")
activate DDBC
DDBC->DDB: store the tenant record
DDB->DDBC: success
deactivate DDB
DDBC->DDTS:success
deactivate DDBC
DDTS->TSI:success
deactivate DDTS
TSI->TSL: success
deactivate TSI
TSL->TC: HTTP 200 OK
deactivate TSL
TC->>U:success message
deactivate TC
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -0,0 +1,60 @@
@startuml
Title: Create a Tenant (NoSQL)
actor "User" as U
participant "Tenant Console" as TC
participant "TenantServiceClient" as TCL
participant "TenantServiceRestV1" as TRS
participant "TenantServiceImpl" as TSI
participant "Cx1TenantService" as CTS
participant "cassandra-driver-core-2.2.0-rc1" as DDC
database "Cassandra" as C
U->TC:create Tenant
note right
The Tenant Console
may be part of the
Admin Console
end note
activate TC
TC->TCL:createTenant()
activate TCL
TCL->TCL: find server from super\nAbstractServiceClient
TCL->TRS: HTTP POST {tenantCtx}/public/an2/v1/tenants\nCreateTenantPojo(JSON)
activate TRS
note right
This is wired
to the endpoint
using Jersey
end note
TRS->TSI: create(TenantServiceSPI=Cx1TenantService)
activate TSI
TSI->CTS: createTenant()
note right
The Cassandra
implementation can
be replaced by
other implementations
(e.g. Dynamo DB)
through Spring config
end note
activate CTS
CTS->DDC: insert into Table alf_data_tenants
activate DDC
DDC->C: store the tenant record
C->DDC:success
deactivate C
DDC->CTS: success
deactivate DDC
CTS->TSI:success
deactivate CTS
TSI->TRS: success
deactivate TSI
TRS->TCL: HTTP 200 OK
deactivate TRS
TCL->TC: success
deactivate TCL
TC->>U:success message
deactivate TC
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -0,0 +1,175 @@
@startuml
title Policies: Policy Component (V4.2 onwards)
' Split into 2 pages
page 2x1
interface PolicyEndpointService #DDDDDD
class PolicyEndpointServiceImpl #DDDDDD implements PolicyEndpointService{
- policyComponent : PolicyComponent
- policyEndpointRegistry : registry
+ registerPolicyEndpoint(QName policy, String endpoint) : void
+ registerPolicyEndpoint(QName policy, QName typeOrAspect, String endpoint) : void
+ unregisterPolicyEndpoint(QName policy, String endpoint) : void
+ unregisterPolicyEndpoint(QName policy, QName typeOrAspect, String endpoint) : void
}
PolicyEndpointServiceImpl -> PolicyComponent
class PolicyEndpointRegistry #DDDDDD {
- QueuedBehaviour dynamicBehaviour
- Set<PolicyEndPointPolicyEndpoint> registrations
+ {static} PolicyEndpointRegistry getInstance()
+ reload(long fromTime)
+ slip(String body, @Properties Map<String, Object> properties)
}
PolicyEndpointRegistry *- "1" QueuedBehaviour
PolicyEndpointServiceImpl -> PolicyEndpointRegistry
class PolicyEndpoint <<immutable>> #DDDDDD {
- QName policy
- QName typeOrAspect
- String endpoint
- long modified
- boolean active
+ getKey()
}
PolicyEndpointRegistry *- PolicyEndpoint
interface Policy
interface ClassPolicy extends Policy
interface OnCreateNodePolicy extends ClassPolicy {
+QNAME: http://www.alfresco.org:onCreateNode
+onCreateNode(ChildAssociationRef childAssocRef)
}
interface AssociationPolicy extends Policy
interface OnCreateChildAssociationPolicy extends AssociationPolicy {
+QNAME: http://www.alfresco.org:onCreateChildAssociation
+onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
}
enum NotificationFrequency {
EVERY_EVENT,
FIRST_EVENT,
TRANSACTION_COMMIT
}
interface Behaviour {
+ <T> getInterface(Class<T> policy) : T
+ disable()
+ enable()
+ isEnabled() : boolean
+ getNotificationFrequency() : NotificationFrequency
}
class BaseBehaviour implements Behaviour {
# proxies : Map<Class, Object>
# frequency : NotificationFrequency
- disabled : StackThreadLocal
+ disable()
+ enable()
+ isEnabled() : boolean
+ getNotificationFrequency() : NotificationFrequency
}
class JavaBehaviour extends BaseBehaviour {
+ <T> getInterface(Class<T> policy) : T
# <T> getInvocationHandler(Object instance, String method, Class<T> policyIF) : InvocationHandler
}
class QueuedBehaviour <<V5.2>> #DDDDDD extends BaseBehaviour {
- ProducerTemplate queueTemplate
+ <T> getInterface(Class<T> policy) : T
# <T> getInvocationHandler(Object instance, String method, Class<T> policyIF) : InvocationHandler
}
class ScriptBehaviour extends BaseBehaviour
BaseBehaviour o- NotificationFrequency
interface BehaviourBinding {
+ generaliseBinding() : BehaviourBinding
}
class ClassBehaviourBinding implements BehaviourBinding {
+ generaliseBinding() : BehaviourBinding
}
class ClassFeatureBehaviourBinding extends ClassBehaviourBinding {
}
class ServiceBehaviourBinding implements BehaviourBinding {
+ generaliseBinding() : BehaviourBinding
}
class ClassPolicyDelegate<P extends ClassPolicy> {
- dictionary : DictionaryService
- factory : CachedPolicyFactory<ClassFeatureBehaviourBinding, P>
# ClassPolicyDelegate(DictionaryService dictionary, Class<P> policyClass, BehaviourIndex<ClassBehaviourBinding> index, long tryLockTimeout)
}
class AssociationPolicyDelegate<P extends AssociationPolicy> {
- dictionary : DictionaryService
- factory : CachedPolicyFactory<ClassFeatureBehaviourBinding, P>
# AssociationPolicyDelegate(DictionaryService dictionary, Class<P> policyClass, BehaviourIndex<ClassFeatureBehaviourBinding> index, long tryLockTimeout)
}
class PropertyPolicyDelegate<P extends PropertyPolicy> {
- dictionary : DictionaryService
- factory : CachedPolicyFactory<ClassFeatureBehaviourBinding, P>
# PropertyPolicyDelegate(DictionaryService dictionary, Class<P> policyClass, BehaviourIndex<ClassFeatureBehaviourBinding> index, long tryLockTimeout)
}
class PolicyFactory<B extends BehaviourBinding, P extends Policy> {
- index : BehaviourIndex~<B>
- policyClass : Class~<P>
- transactionHandlerFactory : TransactionInvocationHandlerFactory
- tenantService : TenantService
--
PolicyFactory(Class<P> policyClass, BehaviourIndex~<B> index)
--
}
class CachedPolicyFactory<B extends BehaviourBinding, P extends Policy> extends PolicyFactory
abstract class AbstractNodeServiceImpl implements NodeService {
- policyComponent : PolicyComponent
# dictionaryService : DictionaryService
# transactionService : TransactionService
# tenantService : TenantService
- onCreateNodeDelegate : ClassPolicyDelegate<OnCreateNodePolicy>
}
interface PolicyComponent {
+ <P extends ClassPolicy> registerClassPolicy(Class<P> policy) : ClassPolicyDelegate<P>
+ <P extends PropertyPolicy> registerPropertyPolicy(Class<P> policy) : PropertyPolicyDelegate<P>
+ <P extends AssociationPolicy> registerAssociationPolicy(Class<P> policy) : AssociationPolicyDelegate<P>
+ bindClassBehaviour(QName policy, QName className, Behaviour behaviour) : BehaviourDefinition<ClassBehaviourBinding>
+ bindClassBehaviour(QName policy, Object service, Behaviour behaviour) : BehaviourDefinition<ServiceBehaviourBinding>
+ bindPropertyBehaviour(QName policy, QName className, QName propertyName, Behaviour behaviour) : BehaviourDefinition<ClassFeatureBehaviourBinding>
+ bindPropertyBehaviour(QName policy, QName className, Behaviour behaviour) : BehaviourDefinition<ClassFeatureBehaviourBinding>
+ bindPropertyBehaviour(QName policy, Object service, Behaviour behaviour) : BehaviourDefinition<ServiceBehaviourBinding>
+ bindAssociationBehaviour(QName policy, QName className, QName assocName, Behaviour behaviour) : BehaviourDefinition<ClassFeatureBehaviourBinding>
+ bindAssociationBehaviour(QName policy, QName className, Behaviour behaviour) : BehaviourDefinition<ClassFeatureBehaviourBinding>
+ bindAssociationBehaviour(QName policy, Object service, Behaviour behaviour) : BehaviourDefinition<ServiceBehaviourBinding>
+ removeClassDefinition(BehaviourDefinition<ClassBehaviourBinding> definition) : void
}
class PolicyComponentImpl implements PolicyComponent {
- Map<QName, ClassBehaviourIndex<ClassBehaviourBinding>> classBehaviours
- Map<QName, ClassBehaviourIndex<ClassFeatureBehaviourBinding>> propertyBehaviours
- Map<QName, ClassBehaviourIndex<ClassFeatureBehaviourBinding>> associationBehaviours
+ PolicyComponentImpl(DictionaryService dictionary)
+ ... (all)
}
interface BehaviourFilter {
+ disableBehaviour() : void
+ disableBehaviour(QName className) : void
+ disableBehaviour(QName className, boolean includeSubClasses) : void
+ disableBehaviour(NodeRef nodeRef, QName className) : void
+ disableBehaviour(NodeRef nodeRef) : void
+ enableBehaviour() : void
+ enableBehaviour(QName className) : void
+ enableBehaviour(NodeRef nodeRef, QName className) : void
+ enableBehaviour(NodeRef nodeRef) : void
}
class BehaviourFilterImpl implements BehaviourFilter {
+ ... (all)
}
AbstractNodeServiceImpl -> PolicyComponentImpl
PolicyComponentImpl -> BehaviourFilterImpl
PolicyComponentImpl -> "creates" ClassPolicyDelegate
PolicyComponentImpl -> "creates" AssocationPolicyDelegate
PolicyComponentImpl -> "creates" PropertyPolicyDelegate
ClassPolicyDelegate --> "uses" PolicyFactory
AssociationPolicyDelegate --> "uses" PolicyFactory
PropertyPolicyDelegate --> "uses" PolicyFactory
PolicyFactory --> "creates" BehaviourBinding
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,56 @@
@startuml
title Policies: Queued Policies (V5.2 Proposal)
actor user
database ActiveMQ as AMQ
database DB {
folder alf_policies
}
component "Client Application" {
component [Client Code]
component [ClientQueueReceiver]
component [Camel(Client App)]
}
user <--> [Client Code]
ClientQueueReceiver <-- [Camel(Client App)]
ClientQueueReceiver -> [Client Code]
[Camel(Client App)] <- AMQ
component "Alfresco One Platform" {
component Quartz as Q
component [Camel] as Camel
component [Policy ReST API] as PR
component PolicyService as PS {
[PolicyCheckJob] as PCJ
[PolicyMap] as PM <<Map>>
component Routes as R {
component ToQueue
component FromQueue
}
}
component PolicyComponent as PC {
component QueuedBehaviour as QB
}
component [Alfresco Services] as Services
component PolicyDAO as PD
}
[Client Code] <-> PR
Q --> PCJ
PCJ -> PM
PR --> PS
Services -> PC
PCJ --> PD
PD -> DB
QB -> ToQueue
ToQueue -> Camel
FromQueue <- Camel
FromQueue --> Services
Camel <-> AMQ
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,37 @@
@startuml
Title: Policies: Register Policy Endpoint (V5.2 Proposal)
skinparam componentStyle uml2
actor "Client App" as Client
participant "Policy Endpoint Rest API" as API
participant "PolicyEndpointService" as PS
participant "PolicyEndpointRegistry" as PER
participant "PolicyEndpointDAO" as DAO
database DB
participant "PolicyComponent" as PC
database AMQ
note over DAO,DB
UNIQUE : policy,typeOrAspect,endpoint
OTHER : active, modified
SORT : modified
end note
Client -> API
API -> PS : registerPolicyEndpoint(policy, typeOrAspect, endpoint)
PS -> DAO : createPolicyEndpoint(policy, typeOrAspect, endpoint)
DAO -> DB : INSERT
PS <-- DAO : success
PS -> PER : reload(fromTime)
PER -> DAO : getPolicyEndpoints(fromTime)
loop each policy endpoint registration change
PER -> PER
end
PS <-- PER : success
API <-- PS : success
Client <-- API : OK
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,48 @@
@startuml
Title: Policies: Reload Policy Endpoints (V5.2 Proposal)
skinparam componentStyle uml2
participant "Quartz"
participant "PolicyCheckJob" as PCJ
participant "PolicyEndpointRegistry" as PER
participant "QueuedBehaviour" as QB
participant "PolicyEndpointDAO" as DAO
database DB
participant "PolicyComponent" as PC
database AMQ
== Static Route Initialization ==
activate PER
PER -> QB: new
activate PER
PER -> PER: from("direct:policy")
PER -> PER: dynamicRouter(method(PolicyEndpointRegistry.class, "slip"))
deactivate PER
deactivate PER
== Quartz ==
note over DAO,DB
UNIQUE : policy,typeOrAspect,endpoint
OTHER : active, modified
SORT : modified
end note
Quartz -> PCJ
PCJ -> PER : reload(fromTime)
PER -> DAO : getPolicyEndpoints(fromTime)
DAO -> DB: SELECT(fromTime)
DAO <-- DB
PER <-- DAO
loop each policy endpoint registration change
PER -> PER: updateRegistrations(PolicyEndpoint)
PER -> PC: bindClassBehaviour(policy,typeOrAspect, behaviour)
end
PCJ <-- PER : success
Quartz <-- PCJ : success
@enduml

View File

@@ -0,0 +1,244 @@
## Queue
![Completeness Badge](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square)
![Version Badge](https://img.shields.io/badge/Version-Future-blue.svg?style=flat-square)
### Purpose
The Queue Component is designed to meet the needs to asynchronous operations.
***
### Overview
The Queue Component manages a set of **Queues** and **Topics** that enable Alfresco components to communicate with each other asynchronously using Messages.
***
### Artifacts and Guidance
* Source Code Link: Not yet known
* License: Not yet known
* Issue Tracker Link: Not yet known
* Documentation Link: Not yet known
* Contribution Model: undetermined
***
### Prerequisite Knowledge
* [Apache Camel](http://camel.apache.org/)
* [Java Message Service](http://docs.oracle.com/javaee/6/tutorial/doc/bncdq.html)
* [AMQP](http://www.amqp.org/)
***
### Design
#### Technology Options
##### JMS and AMQP
There are two alternatives for client interactions with the Queue:
[JMS](http://docs.oracle.com/javaee/6/tutorial/doc/bncdq.html) and [AMQP](https://www.amqp.org/) .
JMS standardizes access at the API layer, thus making it easy to develop Java messaging clients.
AMQP standardizes the wire protocol, making it possible to develop clients in other programming languages.
The design is assuming the use of JMS by the Alfresco services for the following reasons:
1. Wider Adoption among brokers, in particular by AWS SNS should we decide to support that broker
2. Simpler client model for Java, which is an advantage since most of Alfresco is written in Java
However, ActiveMQ supports both JMS access and AMQP. So, when ActiveMQ is used as the message broker,
a client can use AMQP or JMS. This allows a wider range of clients to be developed, such as C and Python clients.
The [Apache Messaging Toolkit](http:/qpid.apache.org/proton/) provides a useful set of libraries that make it easy to
develop such clients,
##### Message Broker
There are a number of alternative implementations available for the Message Broker. These include ActiveMQ, Rabbit MQ, AWS SNS and others. This design is assuming ActiveMQ for the following reasons:
1. It has the most capability
2. Friendly License
3. We have the most knowledge of the technology
See the article [Distributed Queues](https://ts.alfresco.com/share/page/site/eng/wiki-page?title=Distributed_Queues) for a more complete discussion.
#### Delivery Mode
All Messages are sent as *persistent*. This means that the broker will assure that it survives the life of the broker by writing the message to disk (See *Security Considerations*).
#### Subscription Policy
Subscriptions to Topics are typically *durable* to assure that Message Consumers receive all messages, even when the Message Consumer is not active.
But no enforcement of that Subcription policy is done by this component.
#### Embedded Message Brokers
In addition to using this component for messaging, other components may embed a Message Broker in order to manage internal messages. These internal brokers are not part of the responsibility of this component.
#### Component Model
![Components](./resource/component/queue-components.png)
#### Data Model
##### Queues
*Queues* are used to send a Message from one Message Producer to one Message Consumer. Thus, they enable a *point-to-point* style of communication. This design does not use *Queues* (despite the component name).
##### Topics
*Topics* are used to send a Message from one Message Producer to multiple Message Consumers. A Message Producer writes the Message to a Topic. Message Consumers, which subscribe to the *Topic*, receive the Messages. Thus, *Topics* enable a *pub/sub* style of communication. This design assumes messages send via *Topics*
Topics are organized in the following hierarchy.
* System (alf)
* Content (alf.content)
* Node (alf.content.node)
* File (alf.content.file)
* Folder (alf.content.folder)
* Site (alf.content.site)
* Comment (alf.content.comment)
* Rating (alf.content.rating)
* Rendition (alf.content.rendition)
* Identity
* User (alf.identity.user)
* Group (alf.identity.group)
* System (alf.identity.system)
* Model (alf.model)
* Tag (alf.tag)
* Job (alf.job)
* Preference (alf.preference)
* Workflow (alf.workflow)
* Process (alf.workflow.process)
* Task (alf.workflow.task)
This will allow Message Consumers to be selective when deciding what Messages to listen for. For example, the Audit component can subscribe to all changes in the System by subcribing to **alf.*** whereas the Transform component may only subscribe to **alf.content.file.*** messages
##### Messages
###### Format
The Structure of Messages adhere to the *Alfresco Message Style Guidelines*.
![Design Note](https://img.shields.io/badge/Design-Note-orange.svg?style=flat-square) We need to define where that Guideline document is.
Each Message consists two parts:
* Header
* Body
![Message Structure](./resource/component/message-format.png)
###### Header
The header contains system information common to all Messages, such as the time it was sent and the kind of Message it is. Additionally, the header contains the following Alfresco-specific information, stored as keyword/value properties [**Note:** Some of this information will be provided in the *Alfresco Message Style Guidelines*.
* **alf.version**: The Version of the Message in x.y format where x is a major version and y is a minor version.
* **alf.sequenceNumber**: An integer generated by the component that can be used to order messages
###### Body
The body contains the Message payload specified as a JSON object. In a JMS client, that body is of type *javax.jms.TextMessage*. On the wire (AMQP) it is an *AmqpValue* holding a String.
#### Data Dictionary
Not Applicable
### Flows
#### Example of a message created by one service and used by two others
![Model Created Message Flow](./resource/sequence/model-created-flow.png)
#### Example of how a mix of AMQP and JMS clients can access a message topic
![Mixed JMS and AMQP Message Flow](./resource/sequence/jms-amqp-client.png)
#### Class Diagram
***
### APIs and Interfaces
#### Message Registry
The Message Registry is defined in a yaml file that conforms to the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification).
See [Alfresco Message Explorer](https://github.com/Alfresco/message-explorer/blob/master/README.md)
##### REST API
![Design Note](https://img.shields.io/badge/Design-Note-orange.svg?style=flat-square)
We will use Swagger for specifying the REST API. For now, here are the services:
* **Get Topics**
* **Register Topic**
<pre>
POST /topics
{
"endpointName": "alf.content.file.v1.create",
"endpointType": "topic"
"messageSchema": "org.alfresco.message.file.v1.FileCreate"
}
</pre>
![Design](https://img.shields.io/badge/Design-TODO-orange.svg?style=flat-square) Do we need this REST API at all?
* rgauss: I believe in the current design consumers of messages are talking directly to the broker. Those consumers must also have been coded to know how to deal with the message schema of the endpoint they wish to listen to. Do we expect these topic names to change per deployment? If not, then I think they should be treated much like a REST URL in that it's helpful for developers to have documentation in the form of a topic explorer to learn about them, but that may not require that various components register their endpoints via another REST API.
* rgauss: If we do need a method of registering endpoints, we've also discussed the possibility of allowing that registration to happen via messaging rather than REST. A microservice could periodically send a type of heartbeat message containing its endpoint data to a known topic which the queue service could consume. This has a few advantages:
* The queue service would not be required to persist the list of endpoints. After queue service restart it would just gather the heartbeat data again and the microservices would not have to be notified of a queue service restart, asking them to re-register.
* Eliminates the need for a 'de-register' endpoint as the endpoint data can be expired if it's not seen in heartbeat messages after some time.
#### Client API
##### Java
[JMS provides the Java API](http://docs.oracle.com/javaee/1.4/api/javax/jms/package-summary.html)
##### Python
[Apache Messaging Toolkit - Python](http://qpid.apache.org/releases/qpid-proton-0.14.0/proton/python/api/index.html)
##### C/C++
[Apache Messaging Toolkit - C API](http://qpid.apache.org/releases/qpid-proton-0.14.0/proton/c/api/files.html)
![Design Note](https://img.shields.io/badge/Design-Note-orange.svg?style=flat-square)
More API Bindings are available, if the broker supports AMQP.
***
### Configuration
***
### Performance Considerations
![Design Note](https://img.shields.io/badge/Design-Note-orange.svg?style=flat-square) Add a link to a list of Requirement Specifications that describe the key performance goals for this component.
***
### Security Considerations
* Authentication
* Nothing should be made available without authentication. Message Producer and Consumers must be authenticated. Additionally, each Queue and Topic has an access control policy that controls who can read, write and delete messages. All stored
passwords will be stored in an encrypted manner (http://activemq.apache.org/encrypted-passwords.html).
* Authorisation
* The general principle here is that of least privilege. Each Queue and Topic has an access control policy that controls who can read, write and delete messages.
* Encryption
* Queue communications should be encrypted throughout. Additionally certificate based authentication also brings extra security gains (http://activemq.apache.org/how-do-i-use-ssl.html).
* Access
* Since Messages are sent as persisted, the Broker will write them to disk to assure they will survive a Broker crash.
Care must be taken to assure the disks the Message Broker uses to persist the messages are not accessible by unauthorized users.
***
### Cloud Considerations
An important design topic will be to decide what queue provider to support when the component is deployed to Cloud. When deploying to AWS, consideration should be given to using **SNS** and **SQS**.
***
### Design Decisions
| Decision | Rationale | Date |
| :----------------|:--------------------------| ------------:|
| Use JSON for the message body, not Java serialization| (a) Simpler for Engineers to understand <br>(b) more portable across multiple client languages | 22 Sept, 2016 |
| Clients will subscribe directly to the topics to listen for changes as opposed to providing an endpoint for Alfresco to write to| (a) Simpler for clients since they don't need to create an endpoint <br>(b) more scalable because Alfresco is not a potential bottleneck in needing to post events to multiple endpoints | 03 Oct, 2016 |
| Spring Boot will be used to build the Container | See https://issues.alfresco.com/jira/browse/TAG-11 and https://issues.alfresco.com/jira/browse/TAG-12 | 03 Oct, 2016 |
| Each topic will carry messsages pertaining to a single data type (e.g. User Object) | Simpler for tooling to serialize/deserialize objects from a topic (e.g. using the "@class" annotation) | 10 Oct, 2016 |
| Each topic will carry messsages pertaining to a version of the message format | Simpler for message consumers to only consume messages of a particular version | 10 Oct, 2016 |
| Each message will also carry a version id, nothwithstanding the fact that the topic should only carry messages of a particular type and version | We cannot be certain that message producers will be completely reliable | 10 Oct, 2016 |
| It will be possible for a microservice to register a Topic to the Queue service | (a)Allows a new microservice to be introduced dynamically<br>(b)Eliminates need for microservices to depend on a particular version of the Queue Service | 10 Oct, 2016 |
| The version will be encoded in the package name, e.g. **org.alfresco.message.file.v1.FileCreate** and in the header (to allow filtering)| | 13 Oct, 2016 |
***
### Quiz

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,11 @@
@startuml
entity "Object" as O
frame "AMQP Message" as M {
frame header as H
frame "body (JSON)" as B
}
O <.--.> B
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,42 @@
@startuml
title Components Sharing a Model
left to right direction
node "Message Broker" as MB {
queue "Model Topic\nEndpoint" as MTE #white
}
database "NoSQL\n(Schema Data)" as DB1
database "NoSQL\n(Metadata)" as DB2
database "Solr 6.x" as Solr
node "API Gateway" as AG
node "Model\nService" as MS {
node "REST API" as API
node "Message Producer" as MP
}
node "Search Service" as SS {
node "Message Consumer" as L1
}
node "Repository\nService" as R {
node "Message Consumer" as L2
}
node "Model Manager App" as MMA
actor "user" as U
MS <-> DB1 : read/write model
MP -> MTE : model\nchanged message
R <-> DB2 : read/write metadata
SS <-> Solr : read/write
L1 <- MTE : model\nchanged message
L2 <- MTE : model\nchanged message
MMA -> AG : get/put model
AG -> API : get/put model
U <-> MMA : design model
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,41 @@
@startuml
Title Queue Components
left to right direction
actor "Administrator" as A
node "Queue Service" as Q {
node "REST API" as R1 #white
node "Spring Boot" as SB #white
}
node "Message Broker" as MB {
queue "Topic\nEndpoint" as R2 #white
}
node "Message Producer" as MP
node "Message Consumer" as MC1
node "Message Consumer" as MC2
node "Message Consumer" as MC3
node "Message Consumer" as MC4
A-->SB: starts/stops
A-->R1: configures
Q-->R2: starts/stops broker
Q-->R2: configures
MP<--R1: get Topics
MP-->R2: sends message to Topic
R2-->MC1: gets message
R2-->MC2: gets message
R2-->MC3: gets message
R2-->MC4: gets message
R2<--MC1: subscribes
R2<--MC2: subscribes
R2<--MC3: subscribes
R2<--MC4: subscribes
'R2-T
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -0,0 +1,52 @@
@startuml
Title: Mix of AMQP and JMS Messaging Clients
actor "User\n" as U
participant "Python App\n(Apache Qpid App)" as PA
participant "Simple File Share" as SFS
participant "API Gateway" as AG
participant "Repository Service" as RS
participant "File Topic" as FT
database "Content Repository" as CR
autonumber
PA->FT: Subscribe to Topic
U->SFS: Uploads a File
activate SFS
SFS->AG: HTTP POST\nFile
activate AG
AG->RS: HTTP POST\nStore file
activate RS
RS->CR: Store file
activate CR
CR->RS: File stored
deactivate CR
RS->FT: Write message (JMS)
activate FT
note right of FT
alf-file-upload-message
end note
FT->RS: Message written
deactivate FT
RS->AG: 200 Content uploaded
deactivate RS
AG->SFS: 200 Content created
deactivate AG
SFS->U: File uploaded
deactivate SFS
group Message Processed\nBy Python App
autonumber 8
PA->FT: Read Message (AMQP)
note right of FT
alf-file-upload-message
end note
activate FT
FT->PA: Message content
deactivate FT
PA->PA: Process message
PA->FT: wait on next message (AMQP)
end
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -0,0 +1,77 @@
@startuml
Title: Flow for Model Creation Message
actor "User\n" as U
participant "Model Manager App" as MMA
participant "API Gateway" as AG
participant "Search Service" as SS
participant "Model Service" as MS
participant "Repository Service" as RS
participant "Model Topic" as MT
database "Solr Index" as SI
database "Content Repository" as CR
database "Model Database" as MD
autonumber
U->MMA: Creates a New Content Model
activate MMA
MMA->AG: HTTP POST\nStore model
activate AG
AG->MS: HTTP POST\nStore model
activate MS
MS->MD: Store model
activate MD
note right of MD
NoSQL Database
end note
MD->MS: Model stored
deactivate MD
MS->MT: Write message
activate MT
note right of MT
alf-model-created-message
end note
MT->MS: Message written
deactivate MT
MS->AG: 201 Content created
deactivate MS
AG->MMA: 201 Content created
deactivate AG
MMA->U: Model created
deactivate MMA
group Message Processed\nBy Repository Service
autonumber 7
RS->MT: Read message
activate MT
note right of MT
alf-model-created-message
end note
MT->RS: Message content
deactivate MT
RS->RS: Process model
RS->CR: Store model
activate CR
CR->RS: Model stored
deactivate CR
end
group Message Processed\nBy Search Service
autonumber 7
SS->MT: Read message
activate MT
note right of MT
alf-model-created-message
end note
MT->SS: Message content
deactivate MT
SS->SS: Process model
SS->SI: Store model
activate SI
SI->SS: Model stored
deactivate SI
end
@enduml

View File

@@ -0,0 +1,11 @@
# Node Storage and Retrieval
## Properties
### Encrypted properties (```d:encrypted```)
Encrypted properties are stored as BLOBs in the database, but there is no additional handling for
them. In particular, the ```NodeService``` does not encrypt or decrypt them. It only guarantees
that properties of this type contain objects of type ```javax.crypto.SealedObject```. It is up to
the implementor of a custom extension to handle encryption.
The ACS provides the helper class ```MetadataEncryptor``` which provides key handling and a one-stop-shop
for encryption. But custom implementations do not need to use it.

View File

@@ -0,0 +1,122 @@
## Component Name
![Completeness Badge](https://img.shields.io/badge/Document_Level-In_Progress-yellow.svg?style=flat-square)
![Version Badge](https://img.shields.io/badge/Version-5.2-orange.svg?style=flat-square)
### Purpose
***
### Overview
***
### Artifacts and Guidance
* Source Code Link:m https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/
* License: LGPL
* Issue Tracker Link: https://issues.alfresco.com/jira/secure/RapidBoard.jspa?projectKey=REPO&useStoredSettings=true&rapidView=379
* Documentation Link: http://docs.alfresco.com/5.1/concepts/versioning.html
* Contribution Model: Alfresco publishes the source code and will review proposed patch requests
***
### Prerequisite Knowledge
***
### Design
#### Component Model
#### Data Model
#### Data Dictionary
#### Flows
This is a series of flows illustrating when versions are created, based on changes to content and metadata.
##### No Autoversion on Property Updates
Suppose the defaults in the _cm:versionable_ aspect are set as follows:
```
version.store.enableAutoVersioning=true
version.store.enableAutoVersionOnUpdateProps=false
```
Note this is the default case when Alfresco is installed.
![Autoversion on Property Updates](./resource/sequence/noautoversionprops.png)
##### Autoversion on Property Updates
Suppose the defaults in the _cm:versionable_ aspect are set as follows:
```
version.store.enableAutoVersioning=true
version.store.enableAutoVersionOnUpdateProps=true
```
![Autoversion on Property Updates](./resource/sequence/autoversionprops.png)
#### Class Diagram
***
### APIs and Interfaces
***
### Configuration
#### What is Versioned
Whether an object is versionable at all is governed by the presence of the _cm:versionable_ aspect.
If the aspect is present, the object is versioned. Otherwise it is not versioned.
#### Autoversioning
Sometimes it is desirable to create a version automatically. Whether this happens is controlled by two variables in the _cm:versionable_ aspect:
* cm:autoVersion
* cm:autoVersionOnUpdateProps
When _cm:autoVersion_ is true, a new version is created when the _cm:content_ of a content node changes.
When _cm:autoVersionOnUpdateProps_ is true, a new version is created when any of the properties of a content node change.
The defaults for these properties are set in the contentModel.xml file in the usual way. But to simplify the admin experience, the values of these properties can also set using global properties:
* version.store.enableAutoVersioning
* version.store.enableAutoVersionOnUpdateProps
If the values are found in the properties file they have the effect of overriding what may have been set in the contenModel.xml file.
The effect of these properties can be overridden by Share using a set of two properties:
* autoVersion
* autoVersionProps
The values of these overrides are contained in the file _upload.post.config.xml_ such as in this example
```
<autoVersion>true</autoVersion>
<autoVersionProps>false</autoVersionProps>
```
***
### Performance Considerations
***
### Security Considerations
***
### Cloud Considerations
None
***
### Design Decisions
***

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -0,0 +1,107 @@
@startuml
Title: Autoversion on Property Update - Versioning Flow
participant "CMIS Client" as C
participant "Repository" as R
participant "Version Service" as V
participant "workspace://SpacesStore" as SS
participant "workspace://version2Store" as VS
participant "File System" as FS
database "Database" as DB
C->R:HTTP POST
activate R
group "transaction"
R->V
activate V
V->SS: create node
activate SS
SS->DB: create node
activate DB
DB->SS: OK
deactivate DB
SS->V: OK
deactivate SS
note right of SS
workspace://SpacesStore/6060b6b6-2928-4092-ab66-659a7e68c0f6
cm:autoVersionOnUpdateProps=true
cm:name=foo.txt
cm:versionLabel=1.0
end note
V->VS: create version history node with one child node
activate VS
VS->DB: create nodes
activate DB
DB->VS: OK
deactivate DB
VS->V: OK
deactivate VS
note right of VS
One Version History Node with one child ...
workspace://version2Store/62de48fa-6adc-4228-8667-df62584f98de
cm:autoVersionOnUpdateProps=true
cm:name=foo.txt
cm:versionLabel=null
ver2:versionLabel=1.0
ver2:versionDescription=Initial Version
end note
end
V->R: OK
deactivate V
R->C: 200 OK
deactivate R
C->R:HTTP PUT (cm:name=bar.txt)
activate R
group "transaction"
R->V
V->SS: update node
activate V
activate SS
SS->DB: update node
activate DB
DB->SS: OK
deactivate DB
SS->V: OK
deactivate SS
note right of SS
workspace://SpacesStore/6060b6b6-2928-4092-ab66-659a7e68c0f6
cm:autoVersionOnUpdateProps=true
cm:name=bar.txt
cm:versionLabel=1.1
end note
V->VS: create a new child of the version history node
activate VS
VS->DB: create node
activate DB
DB->VS: OK
deactivate DB
VS->V: OK
deactivate VS
note right of VS
One Version History Node with two children...
workspace://version2Store/62de48fa-6adc-4228-8667-df62584f98de
cm:autoVersionOnUpdateProps=true
cm:name=foo.txt
cm:versionLabel=null
ver2:versionLabel=1.0
ver2:versionDescription=Initial Version
NEW CHILD:
workspace://version2Store/64d5fd85-40d3-4a44-b644-d871cb3a1030
cm:autoVersionOnUpdateProps=true
cm:name=bar.txt
cm:versionLabel=1.0
ver2:versionLabel=1.1
ver2:versionDescription=Update Name
end note
end
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1,144 @@
@startuml
Title: Autoversion on Content Update - Versioning Flow
participant "CMIS Client" as C
participant "Repository" as R
participant "Version Service" as V
participant "workspace://SpacesStore" as SS
participant "workspace://version2Store" as VS
participant "File System" as FS
database "Database" as DB
C->R:HTTP POST
activate R
group "transaction"
R->V
activate V
V->SS: create node
activate SS
SS->DB: create node
activate DB
DB->SS: OK
deactivate DB
SS->V: OK
deactivate SS
note right of SS
workspace://SpacesStore/e8cc2b68-7482-4304-a93e-02c758a80954
cm:autoVersionOnUpdateProps=false
cm:name=foo.txt
cm:versionLabel=1.0
end note
V->VS: create version history node with one child node
activate VS
VS->DB: create nodes
activate DB
DB->VS: OK
deactivate DB
VS->V: OK
deactivate VS
note right of VS
One Version History Node with one child ...
workspace://version2Store/ce68aba3-73f6-44f9-ad9b-a9e8d77212de
cm:autoVersionOnUpdateProps=false
cm:name=foo.txt
cm:versionLabel=null
ver2:versionLabel=1.0
ver2:versionDescription=Initial Version
end note
end
V->R: OK
deactivate V
R->C: 200 OK
deactivate R
C->R:HTTP PUT (cm:name=bar.txt)
activate R
group "transaction"
R->V
V->SS: update node
activate V
activate SS
SS->DB: update node
activate DB
DB->SS: OK
deactivate DB
SS->V: OK
deactivate SS
note right of SS
workspace://SpacesStore/e8cc2b68-7482-4304-a93e-02c758a80954
cm:autoVersionOnUpdateProps=false
cm:name=bar.txt
cm:versionLabel=1.0
end note
note right of VS
One Version History Node with one child...
workspace://version2Store/ce68aba3-73f6-44f9-ad9b-a9e8d77212de
cm:autoVersionOnUpdateProps=false
cm:name=foo.txt
cm:versionLabel=null
ver2:versionLabel=1.0
ver2:versionDescription=Initial Version
end note
end
C->R:HTTP PUT (new file content)
activate R
group "transaction"
R->V
activate V
V->SS: update node
activate SS
SS->FS: write file content
activate FS
FS->SS: OK
deactivate FS
SS->DB: update node to point to new file content
activate DB
DB->SS: OK
deactivate DB
SS->V: OK
deactivate SS
note right of SS
workspace://SpacesStore/e8cc2b68-7482-4304-a93e-02c758a80954
cm:autoVersionOnUpdateProps=false
cm:name=bar.txt
cm:versionLabel=1.0
end note
V->VS: create a new child of the version history node
activate VS
VS->DB: create node
activate DB
DB->VS: OK
deactivate DB
VS->V: OK
deactivate VS
note right of VS
One Version History Node with two children...
workspace://version2Store/ce68aba3-73f6-44f9-ad9b-a9e8d77212de
cm:autoVersionOnUpdateProps=false
cm:name=foo.txt
cm:versionLabel=null
ver2:versionLabel=1.0
ver2:versionDescription=Initial Version
NEW CHILD:
workspace://version2Store/9fb3fb08-7cfb-4c0a-ac72-233aaf60fa1e
cm:autoVersionOnUpdateProps=false
cm:name=bar.txt
cm:versionLabel=1.0
ver2:versionLabel=1.1
ver2:versionDescription=Update New File Content
end note
end
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,37 @@
@startuml
title Actions: Asynchronous Actions Classes (V5.1 Current)
interface ActionService {
+ void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsychronously)
}
class ActionServiceImpl implements ActionService {
- ActionTransactionListener transactionListener
- Map<String, AsynchronousActionExecutionQueue> asynchronousActionExecutionQueues
+ void registerAsynchronousActionExecutionQueue(String key, AsynchronousActionExecutionQueue asyncExecQueue)
+ void executeAction(...)
- void addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain)
- List<PendingAction> getPostTransactionPendingActions()
+ postCommit()
- queueAction(PendingAction action)
+ etc(...)
}
interface AsynchronousActionExecutionQueue {
+ void executeAction(RuntimeActionService actionService, Action action, NodeRef actionedUponNodeRef, boolean checkConditions, Set<String> actionChain);
}
class AsynchronousActionExecutionQueueImpl implements AsynchronousActionExecutionQueue {
- ThreadPoolExecutor threadPoolExecutor
- TransactionService transactionService
- PolicyComponent policyComponent
- Map<String, AbstractAsynchronousActionFilter> actionFilters
- String id
+ void init()
+ void executeAction(...)
+ etc(...)
}
AsynchronousActionExecutionQueueImpl o- "1" ActionServiceImpl
AsynchronousActionExecutionQueueImpl "0..*" -o ActionServiceImpl
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,61 @@
@startuml
title Actions: Queued Actions Classes (V5.2 Proposal)
interface ActionService {
+ void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsychronously)
}
class ActionServiceImpl implements ActionService {
- ActionTransactionListener transactionListener
- Map<String, AsynchronousActionExecutionQueue> asynchronousActionExecutionQueues
+ void registerAsynchronousActionExecutionQueue(String key, AsynchronousActionExecutionQueue asyncExecQueue)
+ void executeAction(...)
- <b>void bindPendingActionToTransaction(action, actionedUponNodeRef, checkConditions, actionChain)</b>
- <s>void addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain)</s>
- List<PendingAction> getPostTransactionPendingActions()
+ <b>beforeCommit()</b>
+ <s>postCommit()</s>
- queueAction(PendingAction action)
+ etc(...)
}
interface AsynchronousActionExecutionQueue {
+ void executeAction(RuntimeActionService actionService, Action action, NodeRef actionedUponNodeRef, boolean checkConditions, Set<String> actionChain);
}
class AsynchronousActionExecutionQueueImpl implements AsynchronousActionExecutionQueue {
- <b>ProducerTemplate producerTemplate</b>
- <s>ThreadPoolExecutor threadPoolExecutor</s>
- TransactionService transactionService
- PolicyComponent policyComponent
- Map<String, AbstractAsynchronousActionFilter> actionFilters
- String id
+ void init()
+ void executeAction(...)
+ etc(...)
}
package org::apache::camel {
class ProducerTemplate {
+ void sendBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers)
}
class RouteBuilder {
+ void configure()
+ etc(...)
}
class JacksonDataFormat
}
class QueuedActionProducer extends RouteBuilder {
+ void configure()
}
class QueuedActionReceiver extends RouteBuilder {
+ void configure()
}
AsynchronousActionExecutionQueueImpl o- "1" ActionServiceImpl
AsynchronousActionExecutionQueueImpl "0..*" -o ActionServiceImpl
AsynchronousActionExecutionQueueImpl o- "1" ProducerTemplate
QueuedActionProducer --> "uses" JacksonDataFormat
QueuedActionReceiver --> "uses" JacksonDataFormat
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,63 @@
@startuml
class RuleType {
String name
String displayLabel
}
class Rule {
NodeRef nodeRef
String title
String description
boolean ruleDisabled
boolean executeAsynchronously
boolean isAppliedToChildren
}
class Action
class RuleTrigger
Rule --> "1..*" RuleType
Rule --> "1" Action
RuleType --> "*" RuleTrigger
note left of RuleType
There are three rule types defined by default:
- inbound
- outbound
- update
end note
together {
class BeforeDeleteChildAssociationRuleTrigger
class CreateNodeRuleTrigger
class OnCreateChildAssociationRuleTrigger
class OnMoveNodeRuleTrigger
class OnPropertyUpdateRuleTrigger
class RestoreNodeRuleTrigger
class SingleAssocRefPolicyRuleTrigger
class SingleNodeRefPolicyRuleTrigger
}
CreateNodeRuleTrigger -[hidden]--> BeforeDeleteChildAssociationRuleTrigger
OnMoveNodeRuleTrigger -[hidden]--> OnCreateChildAssociationRuleTrigger
OnPropertyUpdateRuleTrigger -[hidden]--> RestoreNodeRuleTrigger
SingleAssocRefPolicyRuleTrigger -[hidden]--> SingleNodeRefPolicyRuleTrigger
RuleTrigger <|-- BeforeDeleteChildAssociationRuleTrigger
RuleTrigger <|-- CreateNodeRuleTrigger
RuleTrigger <|-- OnCreateChildAssociationRuleTrigger
RuleTrigger <|-- OnMoveNodeRuleTrigger
RuleTrigger <|-- OnPropertyUpdateRuleTrigger
RuleTrigger <|-- RestoreNodeRuleTrigger
RuleTrigger <|-- SingleAssocRefPolicyRuleTrigger
RuleTrigger <|-- SingleNodeRefPolicyRuleTrigger
note right of Action
See separate diagram for info about Actions
end note
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,26 @@
@startuml
left to right direction
skinparam linetype ortho
component Client
component TransformationEngine {
component Service
component Router
component Configuration
}
component AdminConsole
component Log
component TransformationFarm {
component Worker1
component Worker2
component Worker3
}
Client->Service:calls
Service->Router:calls
Router->Configuration:reads
AdminConsole->Configuration:sets
Service->Log:writes
AdminConsole->Log:writes
Router->Worker1:calls
@enduml