mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
Merge pull request #11893 from kobergj/MultiInstanceOcisPartII
[OCISDEV-456] Cross Instance Sharing
This commit is contained in:
5
changelog/unreleased/multi-instance-sharing.md
Normal file
5
changelog/unreleased/multi-instance-sharing.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Enhancement: Allow sharing between instances
|
||||
|
||||
In Multi-Instance ocis it is now possible to share between instances.
|
||||
|
||||
https://github.com/owncloud/ocis/pull/11893
|
||||
@@ -9,10 +9,13 @@ Demo User have different roles on different instances
|
||||
| User | ocis.owncloud.test | ocis.ocm.owncloud.test |
|
||||
| --- | --- | --- |
|
||||
| admin | admin | admin |
|
||||
| einstein | user-light | user-light |
|
||||
| einstein | user | |
|
||||
| katherine | space-admin | |
|
||||
| marie | user-light | user |
|
||||
| moss | | admin | |
|
||||
| richard | user | user-light |
|
||||
| marie | | user |
|
||||
| moss | | admin |
|
||||
| richard | | |
|
||||
|
||||
|
||||
Users can be invited to instances they are not member of by using their exact email address in space membership or share dialog.
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
# groupOfNames requires at least one member to be present
|
||||
# The refint will use this dn if the last member of the group
|
||||
# has been removed
|
||||
dn: cn=nobody,dc=owncloud,dc=com
|
||||
objectClass: top
|
||||
objectClass: organizationalRole
|
||||
description: to be used for refint in empty groups
|
||||
cn: nobody
|
||||
|
||||
dn: cn=ec730a6c-1b63-4b45-b83b-9e2311afdf85,dc=owncloud,dc=com
|
||||
objectClass: top
|
||||
objectClass: organizationalRole
|
||||
description: ocis
|
||||
cn: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
|
||||
dn: cn=8d24cb5f-6ee6-4b98-86df-c4c268dddb46,dc=owncloud,dc=com
|
||||
objectClass: top
|
||||
objectClass: organizationalRole
|
||||
description: ocis.ocm
|
||||
cn: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
@@ -0,0 +1,14 @@
|
||||
# configure memberof overlay to use groupOfNames and member attributes
|
||||
dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcMemberOfGroupOC
|
||||
olcMemberOfGroupOC: groupOfNames
|
||||
-
|
||||
replace: olcMemberOfMemberAD
|
||||
olcMemberOfMemberAD: member
|
||||
|
||||
# configure refint overlay to use nobody if no member is present
|
||||
dn: olcOverlay={1}refint,olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcRefintNothing
|
||||
olcRefintNothing: cn=nobody,dc=owncloud,dc=com
|
||||
@@ -0,0 +1,14 @@
|
||||
# the owncloud organization is already setup by osixia configuration
|
||||
#dn: dc=owncloud,dc=com
|
||||
#objectClass: organization
|
||||
#objectClass: dcObject
|
||||
#dc: owncloud
|
||||
#o: ownCloud
|
||||
|
||||
dn: ou=users,dc=owncloud,dc=com
|
||||
objectClass: organizationalUnit
|
||||
ou: users
|
||||
|
||||
dn: ou=groups,dc=owncloud,dc=com
|
||||
objectClass: organizationalUnit
|
||||
ou: groups
|
||||
132
deployments/examples/ocis_multi/config/ldap/ldif/20_users.ldif
Normal file
132
deployments/examples/ocis_multi/config/ldap/ldif/20_users.ldif
Normal file
@@ -0,0 +1,132 @@
|
||||
# Start dn with uid (user identifier / login), not cn (Firstname + Surname)
|
||||
dn: uid=einstein,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: einstein
|
||||
givenName: Albert
|
||||
sn: Einstein
|
||||
cn: einstein
|
||||
displayName: Albert Einstein
|
||||
description: A German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics (alongside quantum mechanics).
|
||||
mail: einstein@example.org
|
||||
uidNumber: 20000
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/einstein
|
||||
ownCloudUUID: 4c510ada-c86b-4815-8820-42cdf82c3d51
|
||||
owncloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudRole: ocisUser
|
||||
userPassword:: e1NTSEF9TXJEcXpFNGdKbXZxbVRVTGhvWEZ1VzJBbkV3NWFLK3J3WTIvbHc9PQ==
|
||||
|
||||
dn: uid=marie,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: marie
|
||||
givenName: Marie
|
||||
sn: Curie
|
||||
cn: marie
|
||||
displayName: Marie Skłodowska Curie
|
||||
description: A Polish and naturalized-French physicist and chemist who conducted pioneering research on radioactivity.
|
||||
mail: marie@example.org
|
||||
uidNumber: 20001
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/marie
|
||||
ownCloudUUID: f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c
|
||||
owncloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudRole: ocisUser
|
||||
userPassword:: e1NTSEF9UmFvQWs3TU9jRHBIUWY3bXN3MGhHNnVraFZQWnRIRlhOSUNNZEE9PQ==
|
||||
|
||||
dn: uid=richard,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: richard
|
||||
givenName: Richard
|
||||
sn: Feynman
|
||||
cn: richard
|
||||
displayName: Richard Phillips Feynman
|
||||
description: An American theoretical physicist, known for his work in the path integral formulation of quantum mechanics, the theory of quantum electrodynamics, the physics of the superfluidity of supercooled liquid helium, as well as his work in particle physics for which he proposed the parton model.
|
||||
mail: richard@example.org
|
||||
uidNumber: 20002
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/richard
|
||||
ownCloudUUID: 932b4540-8d16-481e-8ef4-588e4b6b151c
|
||||
ownCloudRole: ocisUser
|
||||
userPassword:: e1NTSEF9Z05LZTRreHdmOGRUREY5eHlhSmpySTZ3MGxSVUM1d1RGcWROTVE9PQ==
|
||||
|
||||
dn: uid=katherine,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: katherine
|
||||
givenName: Katherine
|
||||
sn: Johnson
|
||||
cn: johnson
|
||||
displayName: Creola Katherine Johnson
|
||||
description: An American mathematician whose precise orbital calculations were critical to NASA’s early spaceflights, including the Mercury and Apollo missions.
|
||||
mail: katherine@example.org
|
||||
uidNumber: 20002
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/katherine
|
||||
ownCloudUUID: 534bb038-6f9d-4093-946f-133be61fa4e7
|
||||
owncloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudRole: ocisSpaceAdmin
|
||||
userPassword:: e1NTSEF9Z05LZTRreHdmOGRUREY5eHlhSmpySTZ3MGxSVUM1d1RGcWROTVE9PQ==
|
||||
|
||||
dn: uid=moss,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: moss
|
||||
givenName: Maurice
|
||||
sn: Moss
|
||||
cn: moss
|
||||
displayName: Maurice Moss
|
||||
description: A worker in the IT Department of Reynholm Industries. Of all the working staff in the IT Department, he is the most hard-working, the most experienced, and the most capable of doing his job well. He puts a lot of effort into his work, however he does not get the credit he deserves.
|
||||
mail: moss@example.org
|
||||
uidNumber: 20003
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/moss
|
||||
ownCloudUUID: 058bff95-6708-4fe5-91e4-9ea3d377588b
|
||||
owncloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudRole: ocisAdmin
|
||||
userPassword:: e1NTSEF9N0hEdTRoMkFDVExFWWt4U0RtSDZVQjhmUlpKRExDZDc=
|
||||
|
||||
dn: uid=admin,ou=users,dc=owncloud,dc=com
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: ownCloudUser
|
||||
objectClass: person
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
uid: admin
|
||||
givenName: Admin
|
||||
sn: Admin
|
||||
cn: admin
|
||||
displayName: Admin
|
||||
description: An admin for this oCIS instance.
|
||||
mail: admin@example.org
|
||||
uidNumber: 20004
|
||||
gidNumber: 30000
|
||||
homeDirectory: /home/admin
|
||||
ownCloudUUID: ddc2004c-0977-11eb-9d3f-a793888cd0f8
|
||||
owncloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
owncloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudRole: ocisAdmin
|
||||
userPassword:: e1NTSEF9UWhmaFB3dERydTUydURoWFFObDRMbzVIckI3TkI5Nmo=
|
||||
@@ -0,0 +1,95 @@
|
||||
dn: cn=users,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: users
|
||||
description: Users
|
||||
ownCloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: 509a9dcd-bb37-4f4f-a01a-19dca27d9cfa
|
||||
member: uid=einstein,ou=users,dc=owncloud,dc=com
|
||||
member: uid=marie,ou=users,dc=owncloud,dc=com
|
||||
member: uid=richard,ou=users,dc=owncloud,dc=com
|
||||
member: uid=moss,ou=users,dc=owncloud,dc=com
|
||||
member: uid=admin,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=sailing-lovers,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: sailing-lovers
|
||||
description: Sailing lovers
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: 6040aa17-9c64-4fef-9bd0-77234d71bad0
|
||||
member: uid=einstein,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=violin-haters,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: violin-haters
|
||||
description: Violin haters
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: dd58e5ec-842e-498b-8800-61f2ec6f911f
|
||||
member: uid=einstein,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=radium-lovers,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: radium-lovers
|
||||
description: Radium lovers
|
||||
ownCloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudUUID: 7b87fd49-286e-4a5f-bafd-c535d5dd997a
|
||||
member: uid=marie,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=polonium-lovers,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: polonium-lovers
|
||||
description: Polonium lovers
|
||||
ownCloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudUUID: cedc21aa-4072-4614-8676-fa9165f598ff
|
||||
member: uid=marie,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=quantum-lovers,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: quantum-lovers
|
||||
description: Quantum lovers
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: a1726108-01f8-4c30-88df-2b1a9d1cba1a
|
||||
member: uid=richard,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=philosophy-haters,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: philosophy-haters
|
||||
description: Philosophy haters
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: 167cbee2-0518-455a-bfb2-031fe0621e5d
|
||||
member: uid=richard,ou=users,dc=owncloud,dc=com
|
||||
|
||||
dn: cn=physics-lovers,ou=groups,dc=owncloud,dc=com
|
||||
objectClass: groupOfNames
|
||||
objectClass: ownCloud
|
||||
objectClass: top
|
||||
objectClass: ownCloudGroup
|
||||
cn: physics-lovers
|
||||
description: Physics lovers
|
||||
ownCloudMemberOf: ec730a6c-1b63-4b45-b83b-9e2311afdf85
|
||||
ownCloudMemberOf: 8d24cb5f-6ee6-4b98-86df-c4c268dddb46
|
||||
ownCloudUUID: 262982c1-2362-4afa-bfdf-8cbfef64a06e
|
||||
member: uid=einstein,ou=users,dc=owncloud,dc=com
|
||||
member: uid=marie,ou=users,dc=owncloud,dc=com
|
||||
member: uid=richard,ou=users,dc=owncloud,dc=com
|
||||
@@ -0,0 +1,57 @@
|
||||
# This LDIF files describes the ownCloud schema
|
||||
dn: cn=owncloud,cn=schema,cn=config
|
||||
objectClass: olcSchemaConfig
|
||||
cn: owncloud
|
||||
olcObjectIdentifier: ownCloudOid 1.3.6.1.4.1.39430
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.2 NAME 'ownCloudUUID'
|
||||
DESC 'A non-reassignable and persistent account ID)'
|
||||
EQUALITY uuidMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.3 NAME 'oCExternalIdentity'
|
||||
DESC 'A triple separated by "$" representing the objectIdentity resource type of the Graph API ( signInType $ issuer $ issuerAssignedId )'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.4 NAME 'ownCloudUserEnabled'
|
||||
DESC 'A boolean value indicating if ownCloudUser is enabled'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE)
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.5 NAME 'ownCloudUserType'
|
||||
DESC 'User type (e.g. Member or Guest)'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.6 NAME 'ocLastSignInTimestamp'
|
||||
DESC 'The timestamp of the last sign-in'
|
||||
EQUALITY generalizedTimeMatch
|
||||
ORDERING generalizedTimeOrderingMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.7 NAME 'ownCloudMemberOf'
|
||||
DESC 'Instances the user is member of'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.8 NAME 'ownCloudGuestOf'
|
||||
DESC 'Instances the user is guest of'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: ( ownCloudOid:1.1.9 NAME 'ownCloudRole'
|
||||
DESC 'The role of the user on instances they are memberOf'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcObjectClasses: ( ownCloudOid:1.2.1 NAME 'ownCloud'
|
||||
DESC 'ownCloud LDAP Schema'
|
||||
AUXILIARY
|
||||
MAY ( ownCloudUUID ) )
|
||||
olcObjectClasses: ( ownCloudOid:1.2.2 NAME 'ownCloudUser'
|
||||
DESC 'ownCloud User LDAP Schema'
|
||||
SUP ownCloud
|
||||
AUXILIARY
|
||||
MAY ( ocExternalIdentity $ ownCloudUserEnabled $ ownCloudUserType $ ocLastSignInTimestamp $ ownCloudMemberOf $ ownCloudGuestOf $ ownCloudRole) )
|
||||
olcObjectClasses: ( ownCloudOid:1.2.3 NAME 'ownCloudGroup'
|
||||
DESC 'ownCloud Group LDAP Schema'
|
||||
SUP ownCloud
|
||||
AUXILIARY
|
||||
MAY ( ownCloudMemberOf ) )
|
||||
@@ -75,8 +75,7 @@ services:
|
||||
PROXY_USER_CS3_CLAIM: "username"
|
||||
# INSECURE: needed if oCIS / Traefik is using self generated certificates
|
||||
OCIS_INSECURE: "${INSECURE:-true}"
|
||||
OCIS_ADMIN_USER_ID: ""
|
||||
OCIS_EXCLUDE_RUN_SERVICES: "idp"
|
||||
OCIS_EXCLUDE_RUN_SERVICES: "idp,idm"
|
||||
GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false"
|
||||
GRAPH_USERNAME_MATCH: "none"
|
||||
# password policies
|
||||
@@ -84,8 +83,41 @@ services:
|
||||
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp.yaml
|
||||
OCIS_MFA_ENABLED: ${OCIS_MFA_ENABLED:-false}
|
||||
WEB_OIDC_SCOPE: "openid profile email acr"
|
||||
# LDAP
|
||||
OCIS_LDAP_URI: ldap://ldap-server:389
|
||||
OCIS_LDAP_INSECURE: "true"
|
||||
OCIS_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
|
||||
OCIS_LDAP_GROUP_BASE_DN: "ou=groups,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_GROUP_OBJECTCLASS: "groupOfNames"
|
||||
OCIS_LDAP_USER_BASE_DN: "ou=users,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_USER_OBJECTCLASS: "inetOrgPerson"
|
||||
LDAP_LOGIN_ATTRIBUTES: "uid"
|
||||
OCIS_ADMIN_USER_ID: "ddc2004c-0977-11eb-9d3f-a793888cd0f8"
|
||||
IDP_LDAP_LOGIN_ATTRIBUTE: "uid"
|
||||
IDP_LDAP_UUID_ATTRIBUTE: "ownclouduuid"
|
||||
IDP_LDAP_UUID_ATTRIBUTE_TYPE: binary
|
||||
GRAPH_LDAP_SERVER_WRITE_ENABLED: "true" # assuming the external ldap is writable
|
||||
GRAPH_LDAP_REFINT_ENABLED: "true" # osixia has refint enabled.
|
||||
# Multi-Instance Configuration
|
||||
OCIS_MULTI_INSTANCE_ENABLED: true
|
||||
OCIS_MULTI_INSTANCE_INSTANCEID: "base"
|
||||
OCIS_MULTI_INSTANCE_INSTANCEID: "ec730a6c-1b63-4b45-b83b-9e2311afdf85"
|
||||
OCIS_LDAP_USER_FILTER: "(&(objectclass=owncloud)(|(ownCloudMemberOf=ec730a6c-1b63-4b45-b83b-9e2311afdf85)(ownCloudGuestOf=ec730a6c-1b63-4b45-b83b-9e2311afdf85)))"
|
||||
OCIS_LDAP_GROUP_FILTER: "(&(objectclass=owncloud)(ownCloudMemberOf=ec730a6c-1b63-4b45-b83b-9e2311afdf85))"
|
||||
OCIS_LDAP_USER_MEMBER_ATTRIBUTE: "owncloudMemberOf"
|
||||
OCIS_LDAP_USER_GUEST_ATTRIBUTE: "ownCloudGuestOf"
|
||||
OCIS_LDAP_PRECISE_SEARCH_ATTRIBUTE: "cn"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_ENABLED: true
|
||||
OCIS_LDAP_INSTANCE_MAPPER_BASE_DN: "dc=owncloud,dc=com"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_NAME_ATTRIBUTE: "description"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_ID_ATTRIBUTE: "cn"
|
||||
OCIS_MULTI_INSTANCE_QUERY_TEMPLATE: "([^@]+)@(.+).owncloud.test"
|
||||
OCIS_MULTI_INSTANCE_MEMBER_CLAIM: "memberOf"
|
||||
OCIS_MULTI_INSTANCE_GUEST_CLAIM: "guestOf"
|
||||
OCIS_MULTI_INSTANCE_GUEST_ROLE: "user-light"
|
||||
# Workaround needed to show external users - can be removed once fixed
|
||||
OCIS_SHOW_USER_EMAIL_IN_RESULTS: true
|
||||
PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM: ownCloudRole
|
||||
volumes:
|
||||
- ./config/ocis/banned-password-list.txt:/etc/ocis/banned-password-list.txt
|
||||
- ./config/ocis/csp.yaml:/etc/ocis/csp.yaml
|
||||
@@ -130,17 +162,13 @@ services:
|
||||
PROXY_USER_CS3_CLAIM: "username"
|
||||
# ??
|
||||
OCIS_INSECURE: "${INSECURE:-true}"
|
||||
OCIS_ADMIN_USER_ID: ""
|
||||
OCIS_EXCLUDE_RUN_SERVICES: "idp"
|
||||
OCIS_EXCLUDE_RUN_SERVICES: "idp,idm"
|
||||
GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false"
|
||||
GRAPH_USERNAME_MATCH: "none"
|
||||
# CSP
|
||||
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp-ocm.yaml
|
||||
OCIS_MFA_ENABLED: ${OCIS_MFA_ENABLED:-false}
|
||||
WEB_OIDC_SCOPE: "openid profile email acr"
|
||||
# Multi-Instance
|
||||
OCIS_MULTI_INSTANCE_ENABLED: true
|
||||
OCIS_MULTI_INSTANCE_INSTANCEID: "ocm"
|
||||
# make the REVA gateway accessible to the app drivers
|
||||
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
|
||||
# make the registry available to the app provider containers
|
||||
@@ -149,6 +177,42 @@ services:
|
||||
NATS_NATS_PORT: 9233
|
||||
#keycloak
|
||||
WEB_UI_CONFIG_FILE: /etc/ocis/ocis.ocm.web.config.json
|
||||
# LDAP
|
||||
OCIS_LDAP_URI: ldap://ldap-server:389
|
||||
OCIS_LDAP_INSECURE: "true"
|
||||
OCIS_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
|
||||
OCIS_LDAP_GROUP_BASE_DN: "ou=groups,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_GROUP_OBJECTCLASS: "groupOfNames"
|
||||
OCIS_LDAP_USER_BASE_DN: "ou=users,dc=owncloud,dc=com"
|
||||
OCIS_LDAP_USER_OBJECTCLASS: "inetOrgPerson"
|
||||
LDAP_LOGIN_ATTRIBUTES: "uid"
|
||||
OCIS_ADMIN_USER_ID: "ddc2004c-0977-11eb-9d3f-a793888cd0f8"
|
||||
IDP_LDAP_LOGIN_ATTRIBUTE: "uid"
|
||||
IDP_LDAP_UUID_ATTRIBUTE: "ownclouduuid"
|
||||
IDP_LDAP_UUID_ATTRIBUTE_TYPE: binary
|
||||
GRAPH_LDAP_SERVER_WRITE_ENABLED: "true" # assuming the external ldap is writable
|
||||
GRAPH_LDAP_REFINT_ENABLED: "true" # osixia has refint enabled.
|
||||
# Multi-Instance
|
||||
OCIS_MULTI_INSTANCE_ENABLED: true
|
||||
OCIS_MULTI_INSTANCE_INSTANCEID: "8d24cb5f-6ee6-4b98-86df-c4c268dddb46"
|
||||
OCIS_LDAP_USER_FILTER: "(&(objectclass=owncloud)(|(ownCloudMemberOf=8d24cb5f-6ee6-4b98-86df-c4c268dddb46)(ownCloudGuestOf=8d24cb5f-6ee6-4b98-86df-c4c268dddb46)))"
|
||||
OCIS_LDAP_GROUP_FILTER: "(&(objectclass=owncloud)(ownCloudMemberOf=8d24cb5f-6ee6-4b98-86df-c4c268dddb46))"
|
||||
OCIS_LDAP_USER_MEMBER_ATTRIBUTE: "owncloudMemberOf"
|
||||
OCIS_LDAP_USER_GUEST_ATTRIBUTE: "ownCloudGuestOf"
|
||||
OCIS_LDAP_PRECISE_SEARCH_ATTRIBUTE: "cn"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_ENABLED: true
|
||||
OCIS_LDAP_INSTANCE_MAPPER_BASE_DN: "dc=owncloud,dc=com"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_NAME_ATTRIBUTE: "description"
|
||||
OCIS_LDAP_INSTANCE_MAPPER_ID_ATTRIBUTE: "cn"
|
||||
OCIS_MULTI_INSTANCE_QUERY_TEMPLATE: "([^@]+)@(.+).owncloud.test"
|
||||
OCIS_MULTI_INSTANCE_MEMBER_CLAIM: "memberOf"
|
||||
OCIS_MULTI_INSTANCE_GUEST_CLAIM: "guestOf"
|
||||
OCIS_MULTI_INSTANCE_GUEST_ROLE: "user-light"
|
||||
# user filter required for multi-instance ocis
|
||||
# Workaround needed to show external users - can be removed once fixed
|
||||
OCIS_SHOW_USER_EMAIL_IN_RESULTS: true
|
||||
PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM: ownCloudRole
|
||||
volumes:
|
||||
- ./config/ocis/csp-ocm.yaml:/etc/ocis/csp-ocm.yaml
|
||||
- ./config/ocis/ocis.ocm.web.config.json:/etc/ocis/ocis.ocm.web.config.json:ro
|
||||
@@ -205,6 +269,7 @@ services:
|
||||
# tracing
|
||||
KC_TRACING_ENABLED: ${KEYCLOAK_TRACING:-false}
|
||||
KC_TRACING_ENDPOINT: http://jaeger:4317
|
||||
JAVA_OPTS: "-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.keycloak.entrypoints=https"
|
||||
@@ -218,6 +283,50 @@ services:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
|
||||
ldap-server:
|
||||
image: osixia/openldap:1.5.0
|
||||
networks:
|
||||
ocis-net:
|
||||
environment:
|
||||
LDAP_TLS_VERIFY_CLIENT: never
|
||||
LDAP_TLS: false
|
||||
LDAP_ORGANISATION: owncloud
|
||||
LDAP_DOMAIN: owncloud.com
|
||||
LDAP_ROOT: "dc=owncloud,dc=com"
|
||||
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
|
||||
LDAP_SEED_INTERNAL_LDIF_PATH: /ldifs
|
||||
LDAP_SEED_INTERNAL_SCHEMA_PATH: /schemas
|
||||
ports:
|
||||
- "127.0.0.1:389:389"
|
||||
- "127.0.0.1:636:636"
|
||||
volumes:
|
||||
- ./config/ldap/ldif:/ldifs
|
||||
- ./config/ldap/schemas:/schemas
|
||||
- ldap-certs:/container/service/slapd/assets/certs
|
||||
- ldap-data:/var/lib/ldap
|
||||
- ldap-config:/etc/ldap/slapd.d
|
||||
logging:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
|
||||
ldap-manager:
|
||||
image: osixia/phpldapadmin:latest
|
||||
networks:
|
||||
ocis-net:
|
||||
environment:
|
||||
PHPLDAPADMIN_LDAP_HOSTS: "#PYTHON2BASH:[{'ldap-server': [{'server': [{'port': 389}]}]}]"
|
||||
PHPLDAPADMIN_HTTPS: "false"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.ldap-manager.entrypoints=https"
|
||||
- "traefik.http.routers.ldap-manager.rule=Host(`${LDAP_MANAGER_DOMAIN:-ldap.owncloud.test}`)"
|
||||
- "traefik.http.routers.ldap-manager.tls.certresolver=http"
|
||||
- "traefik.http.routers.ldap-manager.service=ldap-manager"
|
||||
- "traefik.http.services.ldap-manager.loadbalancer.server.port=80"
|
||||
logging:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
certs:
|
||||
ocis-config:
|
||||
@@ -225,6 +334,9 @@ volumes:
|
||||
keycloak_postgres_data:
|
||||
ocis-ocm-config:
|
||||
ocis-ocm-data:
|
||||
ldap-data:
|
||||
ldap-config:
|
||||
ldap-certs:
|
||||
|
||||
networks:
|
||||
ocis-net:
|
||||
|
||||
@@ -627,13 +627,13 @@ type Bundle struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
|
||||
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=ocis.messages.settings.v0.Bundle_Type" json:"type,omitempty" yaml:"type"` // @gotags: yaml:"type"
|
||||
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty" yaml:"extension"` // @gotags: yaml:"extension"
|
||||
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
|
||||
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty" yaml:"settings"` // @gotags: yaml:"settings"
|
||||
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
|
||||
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=ocis.messages.settings.v0.Bundle_Type" json:"type,omitempty"` // @gotags: yaml:"type"
|
||||
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"` // @gotags: yaml:"extension"
|
||||
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
|
||||
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty"` // @gotags: yaml:"settings"
|
||||
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
}
|
||||
|
||||
func (x *Bundle) Reset() {
|
||||
@@ -722,10 +722,10 @@ type Setting struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
|
||||
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
|
||||
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` // @gotags: yaml:"description"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
|
||||
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
|
||||
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // @gotags: yaml:"description"
|
||||
// Types that are assignable to Value:
|
||||
//
|
||||
// *Setting_IntValue
|
||||
@@ -736,7 +736,7 @@ type Setting struct {
|
||||
// *Setting_PermissionValue
|
||||
// *Setting_MultiChoiceCollectionValue
|
||||
Value isSetting_Value `protobuf_oneof:"value"`
|
||||
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
}
|
||||
|
||||
func (x *Setting) Reset() {
|
||||
@@ -867,31 +867,31 @@ type isSetting_Value interface {
|
||||
}
|
||||
|
||||
type Setting_IntValue struct {
|
||||
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type Setting_StringValue struct {
|
||||
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type Setting_BoolValue struct {
|
||||
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
type Setting_SingleChoiceValue struct {
|
||||
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof" yaml:"single_choice_value"` // @gotags: yaml:"single_choice_value"
|
||||
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof"` // @gotags: yaml:"single_choice_value"
|
||||
}
|
||||
|
||||
type Setting_MultiChoiceValue struct {
|
||||
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof" yaml:"multi_choice_value"` // @gotags: yaml:"multi_choice_value"
|
||||
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof"` // @gotags: yaml:"multi_choice_value"
|
||||
}
|
||||
|
||||
type Setting_PermissionValue struct {
|
||||
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof" yaml:"permission_value"` // @gotags: yaml:"permission_value"
|
||||
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof"` // @gotags: yaml:"permission_value"
|
||||
}
|
||||
|
||||
type Setting_MultiChoiceCollectionValue struct {
|
||||
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof" yaml:"multi_choice_collection_value"` // @gotags: yaml:"multi_choice_collection_value"
|
||||
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof"` // @gotags: yaml:"multi_choice_collection_value"
|
||||
}
|
||||
|
||||
func (*Setting_IntValue) isSetting_Value() {}
|
||||
@@ -913,11 +913,11 @@ type Int struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty" yaml:"min"` // @gotags: yaml:"min"
|
||||
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty" yaml:"max"` // @gotags: yaml:"max"
|
||||
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty" yaml:"step"` // @gotags: yaml:"step"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
|
||||
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // @gotags: yaml:"min"
|
||||
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` // @gotags: yaml:"max"
|
||||
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty"` // @gotags: yaml:"step"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
|
||||
}
|
||||
|
||||
func (x *Int) Reset() {
|
||||
@@ -992,11 +992,11 @@ type String struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty" yaml:"required"` // @gotags: yaml:"required"
|
||||
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty" yaml:"min_length"` // @gotags: yaml:"min_length"
|
||||
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty" yaml:"max_length"` // @gotags: yaml:"max_length"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
|
||||
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty"` // @gotags: yaml:"required"
|
||||
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` // @gotags: yaml:"min_length"
|
||||
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` // @gotags: yaml:"max_length"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
|
||||
}
|
||||
|
||||
func (x *String) Reset() {
|
||||
@@ -1071,8 +1071,8 @@ type Bool struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty" yaml:"label"` // @gotags: yaml:"label"
|
||||
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // @gotags: yaml:"label"
|
||||
}
|
||||
|
||||
func (x *Bool) Reset() {
|
||||
@@ -1126,7 +1126,7 @@ type SingleChoiceList struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *SingleChoiceList) Reset() {
|
||||
@@ -1173,7 +1173,7 @@ type MultiChoiceList struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceList) Reset() {
|
||||
@@ -1220,9 +1220,9 @@ type ListOption struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
|
||||
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
|
||||
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
|
||||
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
|
||||
}
|
||||
|
||||
func (x *ListOption) Reset() {
|
||||
@@ -1283,7 +1283,7 @@ type MultiChoiceCollection struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceCollection) Reset() {
|
||||
@@ -1330,10 +1330,10 @@ type MultiChoiceCollectionOption struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
|
||||
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty" yaml:"attribute"` // @gotags: yaml:"attribute"
|
||||
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
|
||||
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
|
||||
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty"` // @gotags: yaml:"attribute"
|
||||
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceCollectionOption) Reset() {
|
||||
@@ -1474,15 +1474,15 @@ type isMultiChoiceCollectionOptionValue_Option interface {
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_IntValue struct {
|
||||
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_StringValue struct {
|
||||
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_BoolValue struct {
|
||||
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*MultiChoiceCollectionOptionValue_IntValue) isMultiChoiceCollectionOptionValue_Option() {}
|
||||
@@ -1496,8 +1496,8 @@ type Permission struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=ocis.messages.settings.v0.Permission_Operation" json:"operation,omitempty" yaml:"operation"` // @gotags: yaml:"operation"
|
||||
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=ocis.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty" yaml:"constraint"` // @gotags: yaml:"constraint"
|
||||
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=ocis.messages.settings.v0.Permission_Operation" json:"operation,omitempty"` // @gotags: yaml:"operation"
|
||||
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=ocis.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty"` // @gotags: yaml:"constraint"
|
||||
}
|
||||
|
||||
func (x *Permission) Reset() {
|
||||
@@ -1552,12 +1552,12 @@ type Value struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// id is the id of the Value. It is generated on saving it.
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty" yaml:"bundle_id"` // @gotags: yaml:"bundle_id"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"` // @gotags: yaml:"bundle_id"
|
||||
// setting_id is the id of the setting from within its bundle.
|
||||
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty" yaml:"setting_id"` // @gotags: yaml:"setting_id"
|
||||
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty" yaml:"account_uuid"` // @gotags: yaml:"account_uuid"
|
||||
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty"` // @gotags: yaml:"setting_id"
|
||||
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` // @gotags: yaml:"account_uuid"
|
||||
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
// Types that are assignable to Value:
|
||||
//
|
||||
// *Value_BoolValue
|
||||
@@ -1682,23 +1682,23 @@ type isValue_Value interface {
|
||||
}
|
||||
|
||||
type Value_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
type Value_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type Value_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type Value_ListValue struct {
|
||||
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof" yaml:"list_value"` // @gotags: yaml:"list_value"
|
||||
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof"` // @gotags: yaml:"list_value"
|
||||
}
|
||||
|
||||
type Value_CollectionValue struct {
|
||||
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof" yaml:"collection_value"` // @gotags: yaml:"collection_value"
|
||||
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof"` // @gotags: yaml:"collection_value"
|
||||
}
|
||||
|
||||
func (*Value_BoolValue) isValue_Value() {}
|
||||
@@ -1716,7 +1716,7 @@ type ListValue struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
|
||||
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
|
||||
}
|
||||
|
||||
func (x *ListValue) Reset() {
|
||||
@@ -1836,15 +1836,15 @@ type isListOptionValue_Option interface {
|
||||
}
|
||||
|
||||
type ListOptionValue_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type ListOptionValue_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type ListOptionValue_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*ListOptionValue_StringValue) isListOptionValue_Option() {}
|
||||
@@ -1858,7 +1858,7 @@ type CollectionValue struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
|
||||
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
|
||||
}
|
||||
|
||||
func (x *CollectionValue) Reset() {
|
||||
@@ -1906,7 +1906,7 @@ type CollectionOption struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// required
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
|
||||
// Types that are assignable to Option:
|
||||
//
|
||||
// *CollectionOption_IntValue
|
||||
@@ -1987,15 +1987,15 @@ type isCollectionOption_Option interface {
|
||||
}
|
||||
|
||||
type CollectionOption_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type CollectionOption_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type CollectionOption_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*CollectionOption_IntValue) isCollectionOption_Option() {}
|
||||
|
||||
@@ -33,8 +33,9 @@ type Config struct {
|
||||
UnifiedRoles UnifiedRoles `yaml:"unified_roles"`
|
||||
MaxConcurrency int `yaml:"max_concurrency" env:"OCIS_MAX_CONCURRENCY;GRAPH_MAX_CONCURRENCY" desc:"The maximum number of concurrent requests the service will handle." introductionVersion:"7.0.0"`
|
||||
|
||||
Keycloak Keycloak `yaml:"keycloak"`
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
Keycloak Keycloak `yaml:"keycloak"`
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
MultiInstance MultiInstanceConfig `yaml:"multi_instance"`
|
||||
|
||||
Validation Validation `yaml:"validation"`
|
||||
|
||||
@@ -92,6 +93,15 @@ type LDAP struct {
|
||||
EducationResourcesEnabled bool `yaml:"education_resources_enabled" env:"GRAPH_LDAP_EDUCATION_RESOURCES_ENABLED" desc:"Enable LDAP support for managing education related resources." introductionVersion:"pre5.0"`
|
||||
EducationConfig LDAPEducationConfig
|
||||
RequireExternalID bool `yaml:"require_external_id" env:"GRAPH_LDAP_REQUIRE_EXTERNAL_ID" desc:"If enabled, the 'OCIS_LDAP_USER_SCHEMA_EXTERNAL_ID' is used as primary identifier for the provisioning API." introductionVersion:"8.0.0"`
|
||||
|
||||
// Multi-Instance Only
|
||||
UserMemberAttribute string `yaml:"user_member_attribute" env:"OCIS_LDAP_USER_MEMBER_ATTRIBUTE" desc:"LDAP Attribute to signal the user is member of an instance. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
UserGuestAttribute string `yaml:"user_guest_attribute" env:"OCIS_LDAP_USER_GUEST_ATTRIBUTE" desc:"LDAP Attribute to signal the user is guest of an instance. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
PreciseSearchAttribute string `yaml:"precise_search_attribute" env:"OCIS_LDAP_PRECISE_SEARCH_ATTRIBUTE" desc:"LDAP Attribute to be used for searching users on other instances. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
InstanceMapperEnabled bool `yaml:"instance_mapper_enabled" env:"OCIS_LDAP_INSTANCE_MAPPER_ENABLED" desc:"The InstanceMapper allows mapping instance names (user readable) to instance IDs (machine readable) based on an LDAP query. See other _INSTANCE_MAPPER_ env vars. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
InstanceMapperBaseDN string `yaml:"instance_mapper_base_dn" env:"OCIS_LDAP_INSTANCE_MAPPER_BASE_DN" desc:"BaseDN of the 'instancename to instanceid' mapper in LDAP. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
InstanceMapperNameAttribute string `yaml:"instance_mapper_name_attribute" env:"OCIS_LDAP_INSTANCE_MAPPER_NAME_ATTRIBUTE" desc:"LDAP Attribute of the instance name. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
InstanceMapperIDAttribute string `yaml:"instance_mapper_id_attribute" env:"OCIS_LDAP_INSTANCE_MAPPER_ID_ATTRIBUTE" desc:"LDAP Attribute of the instance ID. Requires OCIS_MULTI_INSTANCE_ENABLED." introductionVersion:"Curie"`
|
||||
}
|
||||
|
||||
// LDAPEducationConfig represents the LDAP configuration for education related resources
|
||||
@@ -162,3 +172,10 @@ type ServiceAccount struct {
|
||||
type Validation struct {
|
||||
MaxTagLength int `yaml:"max_tag_length" env:"OCIS_MAX_TAG_LENGTH" desc:"Define the maximum tag length. Defaults to 100 if not set. Set to 0 to not limit the tag length. Changes only impact the validation of new tags." introductionVersion:"7.2.0"`
|
||||
}
|
||||
|
||||
// MultiInstanceConfig holds configuration for multi-instance-ocis
|
||||
type MultiInstanceConfig struct {
|
||||
Enabled bool `yaml:"enabled" env:"OCIS_MULTI_INSTANCE_ENABLED" desc:"Enable multiple instances of Infinite Scale." introductionVersion:"Curie"`
|
||||
InstanceID string `yaml:"instanceid" env:"OCIS_MULTI_INSTANCE_INSTANCEID" desc:"The unique ID of this instance." introductionVersion:"Curie"`
|
||||
QueryRegexp string `yaml:"query_regexp" env:"OCIS_MULTI_INSTANCE_QUERY_TEMPLATE" desc:"The regular expression extracting username and instancename from a user provided search." introductionVersion:"Curie"`
|
||||
}
|
||||
|
||||
@@ -36,7 +36,11 @@ type Backend interface {
|
||||
DeleteUser(ctx context.Context, nameOrID string) error
|
||||
// UpdateUser applies changes to given user, identified by username or id
|
||||
UpdateUser(ctx context.Context, nameOrID string, user libregraph.UserUpdate) (*libregraph.User, error)
|
||||
// AddUser adds a user to the instance (multi-instance only)
|
||||
AddUser(ctx context.Context, id string, instanceID string) (libregraph.User, error) // FIXME
|
||||
|
||||
GetUser(ctx context.Context, nameOrID string, oreq *godata.GoDataRequest) (*libregraph.User, error)
|
||||
GetPreciseUser(ctx context.Context, name string, instancename string, oreq *godata.GoDataRequest) (*libregraph.User, error)
|
||||
GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*libregraph.User, error)
|
||||
// FilterUsers returns a list of users that match the filter
|
||||
FilterUsers(ctx context.Context, oreq *godata.GoDataRequest, filter *godata.ParseNode) ([]*libregraph.User, error)
|
||||
|
||||
@@ -42,6 +42,11 @@ func (i *CS3) UpdateUser(ctx context.Context, nameOrID string, user libregraph.U
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
// AddUser is not implemented
|
||||
func (i *CS3) AddUser(ctx context.Context, id string, instanceID string) (libregraph.User, error) {
|
||||
return libregraph.User{}, errNotImplemented
|
||||
}
|
||||
|
||||
// GetUser implements the Backend Interface.
|
||||
func (i *CS3) GetUser(ctx context.Context, userID string, _ *godata.GoDataRequest) (*libregraph.User, error) {
|
||||
logger := i.Logger.SubloggerWithRequestID(ctx)
|
||||
@@ -71,6 +76,11 @@ func (i *CS3) GetUser(ctx context.Context, userID string, _ *godata.GoDataReques
|
||||
return CreateUserModelFromCS3(res.GetUser()), nil
|
||||
}
|
||||
|
||||
// GetPreciseUser is not implemented
|
||||
func (i *CS3) GetPreciseUser(ctx context.Context, name string, instancename string, oreq *godata.GoDataRequest) (*libregraph.User, error) {
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
// GetUsers implements the Backend Interface.
|
||||
func (i *CS3) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*libregraph.User, error) {
|
||||
logger := i.Logger.SubloggerWithRequestID(ctx)
|
||||
|
||||
@@ -76,6 +76,15 @@ type LDAP struct {
|
||||
|
||||
logger *log.Logger
|
||||
conn ldap.Client
|
||||
|
||||
// multi instance only
|
||||
userMemberAttribute string
|
||||
userGuestAttribute string
|
||||
preciseSearchAttribute string
|
||||
instanceMapperEnabled bool
|
||||
instanceMapperBaseDN string
|
||||
instanceMapperNameAttribute string
|
||||
instanceMapperIDAttribute string
|
||||
}
|
||||
|
||||
type userAttributeMap struct {
|
||||
@@ -109,7 +118,7 @@ func ParseDisableMechanismType(disableMechanism string) (DisableUserMechanismTyp
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LDAP, error) {
|
||||
func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger, instanceID string) (*LDAP, error) {
|
||||
if config.UserDisplayNameAttribute == "" || config.UserIDAttribute == "" ||
|
||||
config.UserEmailAttribute == "" || config.UserNameAttribute == "" {
|
||||
return nil, errors.New("invalid user attribute mappings")
|
||||
@@ -158,29 +167,36 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
|
||||
}
|
||||
|
||||
return &LDAP{
|
||||
useServerUUID: config.UseServerUUID,
|
||||
usePwModifyExOp: config.UsePasswordModExOp,
|
||||
userBaseDN: config.UserBaseDN,
|
||||
userFilter: config.UserFilter,
|
||||
userObjectClass: config.UserObjectClass,
|
||||
userIDisOctetString: config.UserIDIsOctetString,
|
||||
userScope: userScope,
|
||||
userAttributeMap: uam,
|
||||
groupBaseDN: config.GroupBaseDN,
|
||||
groupCreateBaseDN: config.GroupCreateBaseDN,
|
||||
groupFilter: config.GroupFilter,
|
||||
groupObjectClass: config.GroupObjectClass,
|
||||
groupIDisOctetString: config.GroupIDIsOctetString,
|
||||
groupScope: groupScope,
|
||||
groupAttributeMap: gam,
|
||||
educationConfig: educationConfig,
|
||||
disableUserMechanism: disableMechanismType,
|
||||
localUserDisableGroupDN: config.LdapDisabledUsersGroupDN,
|
||||
logger: logger,
|
||||
conn: lc,
|
||||
writeEnabled: config.WriteEnabled,
|
||||
refintEnabled: config.RefintEnabled,
|
||||
useExternalID: config.RequireExternalID,
|
||||
useServerUUID: config.UseServerUUID,
|
||||
usePwModifyExOp: config.UsePasswordModExOp,
|
||||
userBaseDN: config.UserBaseDN,
|
||||
userFilter: config.UserFilter,
|
||||
userObjectClass: config.UserObjectClass,
|
||||
userIDisOctetString: config.UserIDIsOctetString,
|
||||
userScope: userScope,
|
||||
userAttributeMap: uam,
|
||||
groupBaseDN: config.GroupBaseDN,
|
||||
groupCreateBaseDN: config.GroupCreateBaseDN,
|
||||
groupFilter: config.GroupFilter,
|
||||
groupObjectClass: config.GroupObjectClass,
|
||||
groupIDisOctetString: config.GroupIDIsOctetString,
|
||||
groupScope: groupScope,
|
||||
groupAttributeMap: gam,
|
||||
educationConfig: educationConfig,
|
||||
disableUserMechanism: disableMechanismType,
|
||||
localUserDisableGroupDN: config.LdapDisabledUsersGroupDN,
|
||||
logger: logger,
|
||||
conn: lc,
|
||||
writeEnabled: config.WriteEnabled,
|
||||
refintEnabled: config.RefintEnabled,
|
||||
useExternalID: config.RequireExternalID,
|
||||
userMemberAttribute: config.UserMemberAttribute,
|
||||
userGuestAttribute: config.UserGuestAttribute,
|
||||
preciseSearchAttribute: config.PreciseSearchAttribute,
|
||||
instanceMapperEnabled: config.InstanceMapperEnabled,
|
||||
instanceMapperBaseDN: config.InstanceMapperBaseDN,
|
||||
instanceMapperNameAttribute: config.InstanceMapperNameAttribute,
|
||||
instanceMapperIDAttribute: config.InstanceMapperIDAttribute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -411,6 +427,26 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.
|
||||
return returnUser, nil
|
||||
}
|
||||
|
||||
// AddUser adds a user to the instance by setting the corresponding guest attribute.
|
||||
func (i *LDAP) AddUser(ctx context.Context, id string, instanceID string) (libregraph.User, error) {
|
||||
e, err := i.getPreciseLDAPUser(id, "")
|
||||
if err != nil {
|
||||
return libregraph.User{}, err
|
||||
}
|
||||
mr := ldap.ModifyRequest{DN: e.DN}
|
||||
mr.Add(i.userGuestAttribute, []string{instanceID})
|
||||
if err := i.conn.Modify(&mr); err != nil {
|
||||
i.logger.Error().Err(err).Str("userid", id).Str("instanceid", instanceID).Msg("error adding user")
|
||||
return libregraph.User{}, err
|
||||
}
|
||||
u, err := i.refineUser(e, nil)
|
||||
if err != nil {
|
||||
i.logger.Error().Err(err).Str("userid", id).Str("instanceid", instanceID).Interface("entry", e).Msg("error refining user")
|
||||
return libregraph.User{}, err
|
||||
}
|
||||
return *u, nil
|
||||
}
|
||||
|
||||
func (i *LDAP) getUserByDN(dn, searchTerm string) (*ldap.Entry, error) {
|
||||
baseFilter := fmt.Sprintf("(objectClass=%s)", i.userObjectClass)
|
||||
|
||||
@@ -524,7 +560,7 @@ func (i *LDAP) getLDAPUserByID(id string) (*ldap.Entry, error) {
|
||||
return nil, fmt.Errorf("invalid User id: %w", err)
|
||||
}
|
||||
filter := fmt.Sprintf("(%s=%s)", i.userAttributeMap.id, idString)
|
||||
return i.getLDAPUserByFilter(filter)
|
||||
return i.getLDAPUserByFilter(filter, i.userFilter)
|
||||
}
|
||||
|
||||
func (i *LDAP) getLDAPUserByNameOrID(nameOrID string) (*ldap.Entry, error) {
|
||||
@@ -538,11 +574,20 @@ func (i *LDAP) getLDAPUserByNameOrID(nameOrID string) (*ldap.Entry, error) {
|
||||
filter = fmt.Sprintf("(%s=%s)", i.userAttributeMap.userName, ldap.EscapeFilter(nameOrID))
|
||||
}
|
||||
|
||||
return i.getLDAPUserByFilter(filter)
|
||||
return i.getLDAPUserByFilter(filter, i.userFilter)
|
||||
}
|
||||
|
||||
func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) {
|
||||
filter = fmt.Sprintf("(&%s(objectClass=%s)%s)", i.userFilter, i.userObjectClass, filter)
|
||||
func (i *LDAP) getPreciseLDAPUser(uniqueID string, instanceID string) (*ldap.Entry, error) {
|
||||
uid := ldap.EscapeFilter(uniqueID)
|
||||
filter := fmt.Sprintf("(%s=%s)", i.userAttributeMap.id, uid)
|
||||
if iid := ldap.EscapeFilter(instanceID); iid != "" {
|
||||
filter = fmt.Sprintf("(&(%s=%s)(|(%s=%s)(%s=%s)))", i.preciseSearchAttribute, uid, i.userMemberAttribute, iid, i.userGuestAttribute, iid)
|
||||
}
|
||||
return i.getLDAPUserByFilter(filter, "") // no user filter for precise search
|
||||
}
|
||||
|
||||
func (i *LDAP) getLDAPUserByFilter(filter string, userFilter string) (*ldap.Entry, error) {
|
||||
filter = fmt.Sprintf("(&%s(objectClass=%s)%s)", userFilter, i.userObjectClass, filter)
|
||||
return i.searchLDAPEntryByFilter(i.userBaseDN, i.getUserAttrTypesForSearch(), filter)
|
||||
}
|
||||
|
||||
@@ -556,6 +601,38 @@ func (i *LDAP) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoData
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var q *godata.GoDataQuery
|
||||
if oreq != nil {
|
||||
q = oreq.Query
|
||||
}
|
||||
return i.refineUser(e, q)
|
||||
}
|
||||
|
||||
// GetPreciseUser gets a user using its exact email address or id. The overall user filter will be ignored.
|
||||
func (i *LDAP) GetPreciseUser(ctx context.Context, name string, instancename string, oreq *godata.GoDataRequest) (*libregraph.User, error) {
|
||||
logger := i.logger.SubloggerWithRequestID(ctx)
|
||||
logger.Debug().Str("backend", "ldap").Msg("GetPreciseUser")
|
||||
|
||||
iid, err := i.getInstanceID(instancename)
|
||||
if err != nil {
|
||||
// error logged in getInstanceID
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
e, err := i.getPreciseLDAPUser(name, iid)
|
||||
if err != nil {
|
||||
i.logger.Error().Err(err).Str("username", name).Str("instancename", instancename).Str("instanceid", iid).Msg("error getting precise user")
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
var q *godata.GoDataQuery
|
||||
if oreq != nil {
|
||||
q = oreq.Query
|
||||
}
|
||||
return i.refineUser(e, q)
|
||||
}
|
||||
|
||||
func (i *LDAP) refineUser(e *ldap.Entry, query *godata.GoDataQuery) (*libregraph.User, error) {
|
||||
u := i.createUserModelFromLDAP(e)
|
||||
if u == nil {
|
||||
return nil, ErrNotFound
|
||||
@@ -568,7 +645,7 @@ func (i *LDAP) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoData
|
||||
}
|
||||
}
|
||||
|
||||
exp, err := GetExpandValues(oreq.Query)
|
||||
exp, err := GetExpandValues(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1352,6 +1429,41 @@ func (i *LDAP) oDataFilterToLDAPFilter(filter *godata.ParseNode) (string, error)
|
||||
return fmt.Sprintf("(%s<=%s)", i.userAttributeMap.lastSignIn, ldap.EscapeFilter(ldapDateTime)), nil
|
||||
}
|
||||
|
||||
func (i *LDAP) getInstanceID(instancename string) (string, error) {
|
||||
if instancename == "" || !i.instanceMapperEnabled {
|
||||
return instancename, nil
|
||||
}
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
i.instanceMapperBaseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 1, 0, false,
|
||||
fmt.Sprintf("(%s=%s)", i.instanceMapperNameAttribute, instancename),
|
||||
[]string{i.instanceMapperIDAttribute},
|
||||
nil,
|
||||
)
|
||||
|
||||
res, err := i.conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
i.logger.Error().Err(err).Str("backend", "ldap").Str("dn", i.instanceMapperBaseDN).Str("instancename", instancename).Str("attribute", i.instanceMapperIDAttribute).Msg("Search instance by name failed")
|
||||
return "", errorcode.New(errorcode.ItemNotFound, "instanceid search failed")
|
||||
}
|
||||
if len(res.Entries) == 0 {
|
||||
// expected behaviour - we log debug in case something is fishy. This log can be removed when the feature proves stable
|
||||
i.logger.Debug().Str("backend", "ldap").Str("dn", i.instanceMapperBaseDN).Str("instancename", instancename).Interface("result", res).Msg("Search instance by name empty")
|
||||
return "", ErrNotFound
|
||||
}
|
||||
if len(res.Entries) > 1 {
|
||||
i.logger.Error().Str("backend", "ldap").Str("dn", i.instanceMapperBaseDN).Str("instancename", instancename).Interface("result", res).Msg("Search instance by name returned multiple responses.")
|
||||
return "", errorcode.New(errorcode.ItemNotFound, "instanceid search returned multiple responses")
|
||||
}
|
||||
if len(res.Entries[0].Attributes) == 0 || len(res.Entries[0].Attributes[0].Values) == 0 {
|
||||
i.logger.Error().Str("backend", "ldap").Str("dn", i.instanceMapperBaseDN).Str("instancename", instancename).Interface("result", res).Msg("Search instance by name returned malformed response")
|
||||
return "", errorcode.New(errorcode.ItemNotFound, "instanceid search response malformed")
|
||||
}
|
||||
return res.Entries[0].Attributes[0].Values[0], nil
|
||||
}
|
||||
|
||||
func isLastSuccessFullSignInDateTimeFilter(node *godata.ParseNode) bool {
|
||||
if node.Token.Type != godata.ExpressionTokenNav {
|
||||
return false
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func getMockedBackend(l ldap.Client, lc config.LDAP, logger *log.Logger) (*LDAP, error) {
|
||||
return NewLDAPBackend(l, lc, logger)
|
||||
return NewLDAPBackend(l, lc, logger, "")
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -80,29 +80,29 @@ func TestNewLDAPBackend(t *testing.T) {
|
||||
|
||||
tc := lconfig
|
||||
tc.UserDisplayNameAttribute = ""
|
||||
if _, err := NewLDAPBackend(l, tc, &logger); err == nil {
|
||||
if _, err := NewLDAPBackend(l, tc, &logger, ""); err == nil {
|
||||
t.Error("Should fail with incomplete user attr config")
|
||||
}
|
||||
|
||||
tc = lconfig
|
||||
tc.GroupIDAttribute = ""
|
||||
if _, err := NewLDAPBackend(l, tc, &logger); err == nil {
|
||||
if _, err := NewLDAPBackend(l, tc, &logger, ""); err == nil {
|
||||
t.Errorf("Should fail with incomplete group config")
|
||||
}
|
||||
|
||||
tc = lconfig
|
||||
tc.UserSearchScope = ""
|
||||
if _, err := NewLDAPBackend(l, tc, &logger); err == nil {
|
||||
if _, err := NewLDAPBackend(l, tc, &logger, ""); err == nil {
|
||||
t.Errorf("Should fail with invalid user search scope")
|
||||
}
|
||||
|
||||
tc = lconfig
|
||||
tc.GroupSearchScope = ""
|
||||
if _, err := NewLDAPBackend(l, tc, &logger); err == nil {
|
||||
if _, err := NewLDAPBackend(l, tc, &logger, ""); err == nil {
|
||||
t.Errorf("Should fail with invalid group search scope")
|
||||
}
|
||||
|
||||
if _, err := NewLDAPBackend(l, lconfig, &logger); err != nil {
|
||||
if _, err := NewLDAPBackend(l, lconfig, &logger, ""); err != nil {
|
||||
t.Errorf("Should fail with invalid group search scope")
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func TestCreateUser(t *testing.T) {
|
||||
|
||||
c := lconfig
|
||||
c.UseServerUUID = true
|
||||
b, _ := NewLDAPBackend(l, c, &logger)
|
||||
b, _ := NewLDAPBackend(l, c, &logger, "")
|
||||
|
||||
newUser, err := b.CreateUser(context.Background(), *user)
|
||||
assert.Nil(t, err)
|
||||
@@ -164,7 +164,7 @@ func TestCreateUserModelFromLDAP(t *testing.T) {
|
||||
l := &mocks.Client{}
|
||||
logger := log.NewLogger(log.Level("debug"))
|
||||
|
||||
b, _ := NewLDAPBackend(l, lconfig, &logger)
|
||||
b, _ := NewLDAPBackend(l, lconfig, &logger, "")
|
||||
if user := b.createUserModelFromLDAP(nil); user != nil {
|
||||
t.Errorf("createUserModelFromLDAP should return on nil Entry")
|
||||
}
|
||||
|
||||
@@ -77,6 +77,64 @@ func (_c *Backend_AddMembersToGroup_Call) RunAndReturn(run func(context.Context,
|
||||
return _c
|
||||
}
|
||||
|
||||
// AddUser provides a mock function with given fields: ctx, id, instanceID
|
||||
func (_m *Backend) AddUser(ctx context.Context, id string, instanceID string) (libregraph.User, error) {
|
||||
ret := _m.Called(ctx, id, instanceID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AddUser")
|
||||
}
|
||||
|
||||
var r0 libregraph.User
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) (libregraph.User, error)); ok {
|
||||
return rf(ctx, id, instanceID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) libregraph.User); ok {
|
||||
r0 = rf(ctx, id, instanceID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(libregraph.User)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, id, instanceID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Backend_AddUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUser'
|
||||
type Backend_AddUser_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// AddUser is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
// - instanceID string
|
||||
func (_e *Backend_Expecter) AddUser(ctx interface{}, id interface{}, instanceID interface{}) *Backend_AddUser_Call {
|
||||
return &Backend_AddUser_Call{Call: _e.mock.On("AddUser", ctx, id, instanceID)}
|
||||
}
|
||||
|
||||
func (_c *Backend_AddUser_Call) Run(run func(ctx context.Context, id string, instanceID string)) *Backend_AddUser_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Backend_AddUser_Call) Return(_a0 libregraph.User, _a1 error) *Backend_AddUser_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Backend_AddUser_Call) RunAndReturn(run func(context.Context, string, string) (libregraph.User, error)) *Backend_AddUser_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CreateGroup provides a mock function with given fields: ctx, group
|
||||
func (_m *Backend) CreateGroup(ctx context.Context, group libregraph.Group) (*libregraph.Group, error) {
|
||||
ret := _m.Called(ctx, group)
|
||||
@@ -528,6 +586,67 @@ func (_c *Backend_GetGroups_Call) RunAndReturn(run func(context.Context, *godata
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetPreciseUser provides a mock function with given fields: ctx, name, instancename, oreq
|
||||
func (_m *Backend) GetPreciseUser(ctx context.Context, name string, instancename string, oreq *godata.GoDataRequest) (*libregraph.User, error) {
|
||||
ret := _m.Called(ctx, name, instancename, oreq)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetPreciseUser")
|
||||
}
|
||||
|
||||
var r0 *libregraph.User
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, *godata.GoDataRequest) (*libregraph.User, error)); ok {
|
||||
return rf(ctx, name, instancename, oreq)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, *godata.GoDataRequest) *libregraph.User); ok {
|
||||
r0 = rf(ctx, name, instancename, oreq)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*libregraph.User)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, *godata.GoDataRequest) error); ok {
|
||||
r1 = rf(ctx, name, instancename, oreq)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Backend_GetPreciseUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPreciseUser'
|
||||
type Backend_GetPreciseUser_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetPreciseUser is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - name string
|
||||
// - instancename string
|
||||
// - oreq *godata.GoDataRequest
|
||||
func (_e *Backend_Expecter) GetPreciseUser(ctx interface{}, name interface{}, instancename interface{}, oreq interface{}) *Backend_GetPreciseUser_Call {
|
||||
return &Backend_GetPreciseUser_Call{Call: _e.mock.On("GetPreciseUser", ctx, name, instancename, oreq)}
|
||||
}
|
||||
|
||||
func (_c *Backend_GetPreciseUser_Call) Run(run func(ctx context.Context, name string, instancename string, oreq *godata.GoDataRequest)) *Backend_GetPreciseUser_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(*godata.GoDataRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Backend_GetPreciseUser_Call) Return(_a0 *libregraph.User, _a1 error) *Backend_GetPreciseUser_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Backend_GetPreciseUser_Call) RunAndReturn(run func(context.Context, string, string, *godata.GoDataRequest) (*libregraph.User, error)) *Backend_GetPreciseUser_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetUser provides a mock function with given fields: ctx, nameOrID, oreq
|
||||
func (_m *Backend) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoDataRequest) (*libregraph.User, error) {
|
||||
ret := _m.Called(ctx, nameOrID, oreq)
|
||||
|
||||
@@ -69,7 +69,8 @@ type DriveItemPermissionsProvider interface {
|
||||
// DriveItemPermissionsService contains the production business logic for everything that relates to permissions on drive items.
|
||||
type DriveItemPermissionsService struct {
|
||||
BaseGraphService
|
||||
tp trace.TracerProvider
|
||||
tp trace.TracerProvider
|
||||
identityBackend identity.Backend
|
||||
}
|
||||
|
||||
type permissionType int
|
||||
@@ -83,7 +84,7 @@ const (
|
||||
)
|
||||
|
||||
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
|
||||
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config, tp trace.TracerProvider) (DriveItemPermissionsService, error) {
|
||||
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config, tp trace.TracerProvider, be identity.Backend) (DriveItemPermissionsService, error) {
|
||||
return DriveItemPermissionsService{
|
||||
BaseGraphService: BaseGraphService{
|
||||
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
|
||||
@@ -91,7 +92,8 @@ func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Sele
|
||||
identityCache: identityCache,
|
||||
config: config,
|
||||
},
|
||||
tp: tp,
|
||||
tp: tp,
|
||||
identityBackend: be,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -190,12 +192,17 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *sto
|
||||
expiration = createShareResponse.GetShare().GetExpiration()
|
||||
default:
|
||||
user, err := s.identityCache.GetUser(ctx, objectID)
|
||||
if errors.Is(err, identity.ErrNotFound) && s.config.IncludeOCMSharees {
|
||||
user, err = s.identityCache.GetAcceptedUser(ctx, objectID)
|
||||
if err == nil && IsSpaceRoot(statResponse.GetInfo().GetId()) {
|
||||
err = errorcode.New(errorcode.InvalidRequest, "federated user can not become a space member")
|
||||
s.logger.Error().Err(err).Str("resourceId", resourceId.GetStorageId()).Interface("userId", objectID).Msg(err.Error())
|
||||
return libregraph.Permission{}, err
|
||||
if errors.Is(err, identity.ErrNotFound) {
|
||||
if s.config.MultiInstance.Enabled {
|
||||
user, err = s.identityBackend.AddUser(ctx, objectID, s.config.MultiInstance.InstanceID)
|
||||
}
|
||||
if s.config.IncludeOCMSharees && err != nil {
|
||||
user, err = s.identityCache.GetAcceptedUser(ctx, objectID)
|
||||
if err == nil && IsSpaceRoot(statResponse.GetInfo().GetId()) {
|
||||
err = errorcode.New(errorcode.InvalidRequest, "federated user can not become a space member")
|
||||
s.logger.Error().Err(err).Str("resourceId", resourceId.GetStorageId()).Interface("userId", objectID).Msg(err.Error())
|
||||
return libregraph.Permission{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -55,7 +55,7 @@ var _ = Describe("createLinkTests", func() {
|
||||
cache := identity.NewIdentityCache(identity.IdentityCacheWithGatewaySelector(gatewaySelector))
|
||||
|
||||
cfg := defaults.FullDefaultConfig()
|
||||
svc, err = service.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg, otel.GetTracerProvider())
|
||||
svc, err = service.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg, otel.GetTracerProvider(), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
driveItemId = &provider.ResourceId{
|
||||
StorageId: "1",
|
||||
|
||||
@@ -80,7 +80,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
cfg.UnifiedRoles.AvailableRoles = slices.DeleteFunc(cfg.UnifiedRoles.AvailableRoles, func(s string) bool {
|
||||
return s == unifiedrole.UnifiedRoleSecureViewerID
|
||||
})
|
||||
service, err := svc.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg, otel.GetTracerProvider())
|
||||
service, err := svc.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg, otel.GetTracerProvider(), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
driveItemPermissionsService = service
|
||||
ctx = revactx.ContextSetUser(context.Background(), currentUser)
|
||||
@@ -270,7 +270,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
// remove SecureViewer from allowed roles for this unit test
|
||||
return s == unifiedrole.UnifiedRoleSecureViewerID
|
||||
})
|
||||
service, err := svc.NewDriveItemPermissionsService(log.NewLogger(), gatewaySelector, cache, cfg, otel.GetTracerProvider())
|
||||
service, err := svc.NewDriveItemPermissionsService(log.NewLogger(), gatewaySelector, cache, cfg, otel.GetTracerProvider(), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleViewerID, unifiedrole.UnifiedRoleSecureViewerID}
|
||||
|
||||
@@ -75,7 +75,7 @@ var _ = Describe("Users changing their own password", func() {
|
||||
GroupSearchScope: "sub",
|
||||
}
|
||||
loggger := log.NewLogger()
|
||||
identityBackend, err = identity.NewLDAPBackend(ldapClient, ldapConfig, &loggger)
|
||||
identityBackend, err = identity.NewLDAPBackend(ldapClient, ldapConfig, &loggger, "")
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
eventsPublisher = mocks.Publisher{}
|
||||
|
||||
@@ -213,7 +213,7 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
return svc, err
|
||||
}
|
||||
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config, options.TraceProvider)
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config, options.TraceProvider, svc.identityBackend)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
@@ -473,7 +473,11 @@ func setIdentityBackends(options Options, svc *Graph) error {
|
||||
TLSConfig: tlsConf,
|
||||
},
|
||||
)
|
||||
lb, err := identity.NewLDAPBackend(conn, options.Config.Identity.LDAP, &options.Logger)
|
||||
var iid string
|
||||
if options.Config.MultiInstance.Enabled {
|
||||
iid = options.Config.MultiInstance.InstanceID
|
||||
}
|
||||
lb, err := identity.NewLDAPBackend(conn, options.Config.Identity.LDAP, &options.Logger, iid)
|
||||
if err != nil {
|
||||
options.Logger.Error().Err(err).Msg("Error initializing LDAP Backend")
|
||||
return err
|
||||
|
||||
@@ -310,6 +310,7 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctxHasFullPerms := g.contextUserHasFullAccountPerms(r.Context())
|
||||
hasMFA := mfa.Has(r.Context())
|
||||
|
||||
if !hasAcceptableSearch(odataReq.Query, g.config.API.IdentitySearchMinLength) {
|
||||
if !ctxHasFullPerms {
|
||||
// for regular user the search term must have a minimum length
|
||||
@@ -357,10 +358,15 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Debug().Interface("query", r.URL.Query()).Msg("calling get users on backend")
|
||||
|
||||
var users []*libregraph.User
|
||||
username, instancename := g.parseExternalSearch(odataReq)
|
||||
|
||||
if odataReq.Query.Filter != nil {
|
||||
switch {
|
||||
case username != "" && instancename != "":
|
||||
users = make([]*libregraph.User, 1)
|
||||
users[0], err = g.identityBackend.GetPreciseUser(r.Context(), username, instancename, odataReq)
|
||||
case odataReq.Query.Filter != nil:
|
||||
users, err = g.applyUserFilter(r.Context(), odataReq, nil)
|
||||
} else {
|
||||
default:
|
||||
users, err = g.identityBackend.GetUsers(r.Context(), odataReq)
|
||||
}
|
||||
|
||||
@@ -1170,3 +1176,21 @@ func (g Graph) searchOCMAcceptedUsers(ctx context.Context, odataReq *godata.GoDa
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// with multi-instance enabled, one can share to another instance by entering `username@instancename`
|
||||
func (g Graph) parseExternalSearch(req *godata.GoDataRequest) (string, string) {
|
||||
if !g.config.MultiInstance.Enabled {
|
||||
return "", ""
|
||||
}
|
||||
if req == nil || req.Query == nil || req.Query.Search == nil {
|
||||
return "", ""
|
||||
}
|
||||
unquoted := strings.Trim(req.Query.Search.RawValue, "\"")
|
||||
parts := regexp.MustCompile(g.config.MultiInstance.QueryRegexp).FindStringSubmatch(unquoted)
|
||||
// parts[0] contains complete expression
|
||||
if len(parts) != 3 {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
return parts[1], parts[2]
|
||||
}
|
||||
|
||||
@@ -103,12 +103,6 @@ func DefaultConfig() *config.Config {
|
||||
MultiFactorAuthentication: config.MFAConfig{
|
||||
AuthLevelNames: []string{"advanced"},
|
||||
},
|
||||
MultiInstance: config.MultiInstanceConfig{
|
||||
InstanceID: "c1f28cf2-d363-4671-a8fe-8d7a80b36b87",
|
||||
MemberClaim: "memberOf",
|
||||
GuestClaim: "guestOf",
|
||||
GuestRole: "user-light",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ func (ra oidcRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *c
|
||||
if overwriteRole == "" {
|
||||
claimRoles, err := extractRoles(ra.rolesClaim, claims)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("Error mapping role names to role ids")
|
||||
logger.Error().Err(err).Str("Claim", ra.rolesClaim).Interface("claims", claims).Msg("Error mapping role names to role ids")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user