REPO-3176: Initial copy of community pages from architecture map and collapsed index page
69
docs/README.md
Normal 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
|
BIN
docs/event-log/audit/resource/data/audit-data.png
Normal file
After Width: | Height: | Size: 25 KiB |
41
docs/event-log/audit/resource/data/audit-data.puml
Normal 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
|
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 206 KiB |
After Width: | Height: | Size: 318 KiB |
@@ -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
|
After Width: | Height: | Size: 427 KiB |
After Width: | Height: | Size: 139 KiB |
@@ -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
|
After Width: | Height: | Size: 491 KiB |
174
docs/identity-provider/authentication/README.md
Normal file
@@ -0,0 +1,174 @@
|
||||
## Authentication
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 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 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 Logoff Flow
|
||||

|
||||
|
||||
##### Kerberos Authentication Login Flow
|
||||

|
||||
|
||||
##### NTLM Authentication Login Flow
|
||||

|
||||
|
||||
#### Class Diagram
|
||||

|
||||
|
||||
|
||||
### 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
|
||||

|
||||
*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
|
||||

|
||||
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
|
||||
|
||||

|
||||
Describe OAuth2 for protection of Cloud REST API's.
|
||||
***
|
||||
|
After Width: | Height: | Size: 180 KiB |
@@ -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
|
260
docs/identity-provider/identity/README.md
Normal file
@@ -0,0 +1,260 @@
|
||||
## Identity
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 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.
|
||||

|
||||
|
||||
#### 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".
|
||||
|
||||
 Do we really need both *System* and *Domain*?
|
||||
|
||||

|
||||
|
||||
#### Data Dictionary
|
||||
|
||||
Not applicable
|
||||
|
||||
#### Flows
|
||||
##### Add a User using Alfresco Admin
|
||||

|
||||
##### OAuth Flow (Alfresco and Box for example)
|
||||

|
||||
##### 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
|
||||

|
||||
##### 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.
|
||||

|
||||
|
||||
#### Class Diagram
|
||||
|
||||
***
|
||||
|
||||
### APIs and Interfaces
|
||||
|
||||
#### REST API
|
||||
 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
|
||||
|
After Width: | Height: | Size: 49 KiB |
@@ -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
|
BIN
docs/identity-provider/identity/resource/data/data-model.png
Normal file
After Width: | Height: | Size: 21 KiB |
@@ -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
|
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 55 KiB |
@@ -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
|
After Width: | Height: | Size: 122 KiB |
@@ -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
|
BIN
docs/identity-provider/identity/resource/sequence/oauth-flow.png
Normal file
After Width: | Height: | Size: 96 KiB |
@@ -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
|
After Width: | Height: | Size: 68 KiB |
@@ -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
|
After Width: | Height: | Size: 383 KiB |
@@ -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
|
After Width: | Height: | Size: 369 KiB |
@@ -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
|
8
docs/infrastructure/README.md
Normal 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)
|
After Width: | Height: | Size: 18 KiB |
@@ -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
|
After Width: | Height: | Size: 68 KiB |
@@ -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
|
After Width: | Height: | Size: 36 KiB |
@@ -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
|
After Width: | Height: | Size: 36 KiB |
@@ -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
|
After Width: | Height: | Size: 65 KiB |
@@ -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
|
After Width: | Height: | Size: 77 KiB |
@@ -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
|
After Width: | Height: | Size: 60 KiB |
@@ -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
|
After Width: | Height: | Size: 79 KiB |
@@ -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
|
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 44 KiB |
@@ -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
|
After Width: | Height: | Size: 42 KiB |
@@ -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
|
After Width: | Height: | Size: 47 KiB |
@@ -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
|
244
docs/messaging/queue/README.md
Normal file
@@ -0,0 +1,244 @@
|
||||
## Queue
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 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
|
||||

|
||||
|
||||
#### 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*.
|
||||
 We need to define where that Guideline document is.
|
||||
|
||||
Each Message consists two parts:
|
||||
* Header
|
||||
* Body
|
||||

|
||||
|
||||
###### 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
|
||||

|
||||
|
||||
#### Example of how a mix of AMQP and JMS clients can access a message topic
|
||||

|
||||
#### 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
|
||||

|
||||
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>
|
||||
|
||||
 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)
|
||||
|
||||

|
||||
More API Bindings are available, if the broker supports AMQP.
|
||||
|
||||
|
||||
***
|
||||
|
||||
### Configuration
|
||||
|
||||
***
|
||||
|
||||
### Performance Considerations
|
||||
 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
|
||||
|
||||
|
BIN
docs/messaging/queue/resource/component/message-format.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
11
docs/messaging/queue/resource/component/message-format.puml
Normal 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
|
After Width: | Height: | Size: 46 KiB |
@@ -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
|
BIN
docs/messaging/queue/resource/component/queue-components.png
Normal file
After Width: | Height: | Size: 35 KiB |
@@ -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
|
After Width: | Height: | Size: 638 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/messaging/queue/resource/sequence/jms-amqp-client.png
Normal file
After Width: | Height: | Size: 53 KiB |
52
docs/messaging/queue/resource/sequence/jms-amqp-client.puml
Normal 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
|
BIN
docs/messaging/queue/resource/sequence/model-created-flow.png
Normal file
After Width: | Height: | Size: 76 KiB |
@@ -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
|
11
docs/meta-data-services/node-storage-and-retrieval/README.md
Normal 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.
|
122
docs/meta-data-services/versions/README.md
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
## Component Name
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 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
|
||||
Suppose the defaults in the _cm:versionable_ aspect are set as follows:
|
||||
```
|
||||
version.store.enableAutoVersioning=true
|
||||
version.store.enableAutoVersionOnUpdateProps=true
|
||||
```
|
||||

|
||||
|
||||
|
||||
#### 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
|
||||
|
||||
***
|
||||
|
||||
|
After Width: | Height: | Size: 94 KiB |
@@ -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
|
After Width: | Height: | Size: 124 KiB |
@@ -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
|
BIN
docs/rules-engine/actions/resource/class/async-actions-class.png
Normal file
After Width: | Height: | Size: 34 KiB |
@@ -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
|
After Width: | Height: | Size: 57 KiB |
@@ -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
|
BIN
docs/rules-engine/rules/resource/class/rule-definition.png
Normal file
After Width: | Height: | Size: 38 KiB |
63
docs/rules-engine/rules/resource/class/rule-definition.puml
Normal 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
|
After Width: | Height: | Size: 18 KiB |
@@ -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
|