Merge pull request #3476 from rhafer/share-ldap-con

[full-ci] adapt for new LDAP config
This commit is contained in:
Jörn Friedrich Dreyer
2022-04-11 22:36:28 +02:00
committed by GitHub
25 changed files with 397 additions and 269 deletions
+12 -14
View File
@@ -1642,8 +1642,7 @@ def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on =
"STORAGE_LDAP_IDP": "https://keycloak/auth/realms/owncloud", "STORAGE_LDAP_IDP": "https://keycloak/auth/realms/owncloud",
"WEB_OIDC_SCOPE": "openid profile email owncloud", "WEB_OIDC_SCOPE": "openid profile email owncloud",
# LDAP bind # LDAP bind
"STORAGE_LDAP_HOSTNAME": "openldap", "STORAGE_LDAP_URI": "ldaps://openldap",
"STORAGE_LDAP_PORT": 636,
"STORAGE_LDAP_INSECURE": "true", "STORAGE_LDAP_INSECURE": "true",
"STORAGE_LDAP_BIND_DN": "cn=admin,dc=owncloud,dc=com", "STORAGE_LDAP_BIND_DN": "cn=admin,dc=owncloud,dc=com",
"STORAGE_LDAP_BIND_PASSWORD": "admin", "STORAGE_LDAP_BIND_PASSWORD": "admin",
@@ -1652,25 +1651,24 @@ def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on =
"PROXY_ACCOUNT_BACKEND_TYPE": "cs3", # proxy should get users from CS3APIS (which gets it from LDAP) "PROXY_ACCOUNT_BACKEND_TYPE": "cs3", # proxy should get users from CS3APIS (which gets it from LDAP)
"PROXY_USER_OIDC_CLAIM": "ocis.user.uuid", # claim was added in Keycloak "PROXY_USER_OIDC_CLAIM": "ocis.user.uuid", # claim was added in Keycloak
"PROXY_USER_CS3_CLAIM": "userid", # equals STORAGE_LDAP_USER_SCHEMA_UID "PROXY_USER_CS3_CLAIM": "userid", # equals STORAGE_LDAP_USER_SCHEMA_UID
"STORAGE_LDAP_BASE_DN": "dc=owncloud,dc=com", "STORAGE_LDAP_GROUP_BASE_DN": "ou=testgroups,dc=owncloud,dc=com",
"STORAGE_LDAP_GROUP_OBJECTCLASS": "groupOfUniqueNames",
"STORAGE_LDAP_GROUPFILTER": "(objectclass=owncloud)",
"STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME": "cn", "STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME": "cn",
"STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER": "gidnumber", "STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER": "gidnumber",
"STORAGE_LDAP_GROUP_SCHEMA_GID": "cn", "STORAGE_LDAP_GROUP_SCHEMA_ID": "cn",
"STORAGE_LDAP_GROUP_SCHEMA_MAIL": "mail", "STORAGE_LDAP_GROUP_SCHEMA_MAIL": "mail",
"STORAGE_LDAP_GROUPATTRIBUTEFILTER": "(&(objectclass=posixGroup)(objectclass=owncloud)({{attr}}={{value}}))", "STORAGE_LDAP_GROUP_SCHEMA_MEMBER": "cn",
"STORAGE_LDAP_GROUPFILTER": "(&(objectclass=groupOfUniqueNames)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))", "STORAGE_LDAP_USER_BASE_DN": "ou=testusers,dc=owncloud,dc=com",
"STORAGE_LDAP_GROUPMEMBERFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))", "STORAGE_LDAP_USER_OBJECTCLASS": "posixAccount",
"STORAGE_LDAP_USERGROUPFILTER": "(&(objectclass=posixGroup)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))", "STORAGE_LDAP_USERFILTER": "(objectclass=owncloud)",
"STORAGE_LDAP_USER_SCHEMA_CN": "cn", "STORAGE_LDAP_USER_SCHEMA_USERNAME": "cn",
"STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME": "displayname", "STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME": "displayname",
"STORAGE_LDAP_USER_SCHEMA_GID_NUMBER": "gidnumber", "STORAGE_LDAP_USER_SCHEMA_GID_NUMBER": "gidnumber",
"STORAGE_LDAP_USER_SCHEMA_MAIL": "mail", "STORAGE_LDAP_USER_SCHEMA_MAIL": "mail",
"STORAGE_LDAP_USER_SCHEMA_UID_NUMBER": "uidnumber", "STORAGE_LDAP_USER_SCHEMA_UID_NUMBER": "uidnumber",
"STORAGE_LDAP_USER_SCHEMA_UID": "ownclouduuid", "STORAGE_LDAP_USER_SCHEMA_ID": "ownclouduuid",
"STORAGE_LDAP_LOGINFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(|(uid={{login}})(mail={{login}})))", "STORAGE_LDAP_LOGIN_ATTRIBUTES": "uid,mail",
"STORAGE_LDAP_USERATTRIBUTEFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)({{attr}}={{value}}))",
"STORAGE_LDAP_USERFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))",
"STORAGE_LDAP_USERFINDFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))",
# ownCloudSQL storage driver # ownCloudSQL storage driver
"STORAGE_HOME_DRIVER": "owncloudsql", "STORAGE_HOME_DRIVER": "owncloudsql",
"STORAGE_USERS_DRIVER": "owncloudsql", "STORAGE_USERS_DRIVER": "owncloudsql",
+39
View File
@@ -0,0 +1,39 @@
Enhancement: Unify LDAP config settings accross services
The storage services where updated to adapt for the recent changes of the LDAP
settings in reva.
Also we allow now to use a new set of top-level LDAP environment variables that
are shared between all LDAP-using services in ocis (graph, idp,
storage-auth-basic, storage-userprovider, storage-groupprovider, idm). This
should simplify the most LDAP based configurations considerably.
Here is a list of the new environment variables:
LDAP_URI
LDAP_INSECURE
LDAP_CACERT
LDAP_BIND_DN
LDAP_BIND_PASSWORD
LDAP_LOGIN_ATTRIBUTES
LDAP_USER_BASE_DN
LDAP_USER_SCOPE
LDAP_USER_FILTER
LDAP_USER_OBJECTCLASS
LDAP_USER_SCHEMA_MAIL
LDAP_USER_SCHEMA_DISPLAY_NAME
LDAP_USER_SCHEMA_USERNAME
LDAP_USER_SCHEMA_ID
LDAP_USER_SCHEMA_ID_IS_OCTETSTRING
LDAP_GROUP_BASE_DN
LDAP_GROUP_SCOPE
LDAP_GROUP_FILTER
LDAP_GROUP_OBJECTCLASS
LDAP_GROUP_SCHEMA_GROUPNAME
LDAP_GROUP_SCHEMA_ID
LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING
Where need these can be overwritten by service specific variables. E.g. it is possible
to use STORAGE_LDAP_URI to overide the top-level LDAP_URI variable.
https://github.com/owncloud/ocis/pull/3476
https://github.com/owncloud/ocis/issues/3150
+2
View File
@@ -5,5 +5,7 @@ Updated reva to version 2.x.x. This update includes:
* TODO * TODO
https://github.com/owncloud/ocis/pull/3430 https://github.com/owncloud/ocis/pull/3430
https://github.com/owncloud/ocis/pull/3476
https://github.com/owncloud/ocis/pull/3482 https://github.com/owncloud/ocis/pull/3482
https://github.com/owncloud/ocis/pull/3497 https://github.com/owncloud/ocis/pull/3497
@@ -58,8 +58,7 @@ services:
STORAGE_LDAP_IDP: https://${KEYCLOAK_DOMAIN:-keycloak.owncloud.test}/auth/realms/${KEYCLOAK_REALM:-owncloud} STORAGE_LDAP_IDP: https://${KEYCLOAK_DOMAIN:-keycloak.owncloud.test}/auth/realms/${KEYCLOAK_REALM:-owncloud}
WEB_OIDC_SCOPE: openid profile email owncloud WEB_OIDC_SCOPE: openid profile email owncloud
# LDAP bind # LDAP bind
STORAGE_LDAP_HOSTNAME: openldap STORAGE_LDAP_URI: "ldaps://openldap"
STORAGE_LDAP_PORT: 636
STORAGE_LDAP_INSECURE: "true" STORAGE_LDAP_INSECURE: "true"
STORAGE_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com" STORAGE_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com"
STORAGE_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin} STORAGE_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
@@ -68,25 +67,22 @@ services:
PROXY_ACCOUNT_BACKEND_TYPE: cs3 # proxy should get users from CS3APIS (which gets it from LDAP) PROXY_ACCOUNT_BACKEND_TYPE: cs3 # proxy should get users from CS3APIS (which gets it from LDAP)
PROXY_USER_OIDC_CLAIM: ocis.user.uuid # claim was added in Keycloak PROXY_USER_OIDC_CLAIM: ocis.user.uuid # claim was added in Keycloak
PROXY_USER_CS3_CLAIM: userid # equals STORAGE_LDAP_USER_SCHEMA_UID PROXY_USER_CS3_CLAIM: userid # equals STORAGE_LDAP_USER_SCHEMA_UID
STORAGE_LDAP_BASE_DN: "dc=owncloud,dc=com" STORAGE_LDAP_GROUP_BASE_DN: "dc=owncloud,dc=com"
STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME: "cn" STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME: "cn"
STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER: "gidnumber" STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER: "gidnumber"
STORAGE_LDAP_GROUP_SCHEMA_GID: "cn" STORAGE_LDAP_GROUP_SCHEMA_ID: "cn"
STORAGE_LDAP_GROUP_SCHEMA_MAIL: "mail" STORAGE_LDAP_GROUP_SCHEMA_MAIL: "mail"
STORAGE_LDAP_GROUPATTRIBUTEFILTER: "(&(objectclass=posixGroup)(objectclass=owncloud)({{attr}}={{value}}))" STORAGE_LDAP_GROUP_SCHEMA_MEMBER: "cn"
STORAGE_LDAP_GROUPFILTER: "(&(objectclass=groupOfUniqueNames)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))" STORAGE_LDAP_GROUP_OBJECTCLASS: "groupOfUniqueNames"
STORAGE_LDAP_GROUPMEMBERFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))" STORAGE_LDAP_GROUPFILTER: "(objectclass=owncloud)"
STORAGE_LDAP_USERGROUPFILTER: "(&(objectclass=posixGroup)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))" STORAGE_LDAP_USER_BASE_DN: "dc=owncloud,dc=com"
STORAGE_LDAP_USER_SCHEMA_CN: "cn" STORAGE_LDAP_USER_SCHEMA_USERNAME: "cn"
STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME: "displayname" STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME: "displayname"
STORAGE_LDAP_USER_SCHEMA_GID_NUMBER: "gidnumber" STORAGE_LDAP_USER_SCHEMA_GID_NUMBER: "gidnumber"
STORAGE_LDAP_USER_SCHEMA_MAIL: "mail" STORAGE_LDAP_USER_SCHEMA_MAIL: "mail"
STORAGE_LDAP_USER_SCHEMA_UID_NUMBER: "uidnumber" STORAGE_LDAP_USER_SCHEMA_UID_NUMBER: "uidnumber"
STORAGE_LDAP_USER_SCHEMA_UID: "ownclouduuid" STORAGE_LDAP_USER_SCHEMA_ID: "ownclouduuid"
STORAGE_LDAP_LOGINFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(|(uid={{login}})(mail={{login}})))" STORAGE_LDAP_LOGIN_ATTRIBUTES: "uid,mail"
STORAGE_LDAP_USERATTRIBUTEFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)({{attr}}={{value}}))"
STORAGE_LDAP_USERFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))"
STORAGE_LDAP_USERFINDFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))"
# ownCloudSQL storage driver # ownCloudSQL storage driver
STORAGE_USERS_DRIVER: owncloudsql STORAGE_USERS_DRIVER: owncloudsql
STORAGE_METADATA_DRIVER: ocis # keep metadata on ocis storage since this are only small files atm STORAGE_METADATA_DRIVER: ocis # keep metadata on ocis storage since this are only small files atm
@@ -608,8 +608,7 @@ services:
STORAGE_USERPROVIDER_ADDR: 0.0.0.0:9144 STORAGE_USERPROVIDER_ADDR: 0.0.0.0:9144
STORAGE_USERPROVIDER_DRIVER: ldap STORAGE_USERPROVIDER_DRIVER: ldap
STORAGE_LDAP_HOSTNAME: glauth STORAGE_LDAP_URI: "ldaps://glauth:9126"
STORAGE_LDAP_PORT: 9126
STORAGE_LDAP_INSECURE: "true" STORAGE_LDAP_INSECURE: "true"
STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva} STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva}
STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test} STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test}
@@ -639,8 +638,7 @@ services:
STORAGE_GROUPPROVIDER_ADDR: 0.0.0.0:9160 STORAGE_GROUPPROVIDER_ADDR: 0.0.0.0:9160
STORAGE_GROUPPROVIDER_DRIVER: ldap STORAGE_GROUPPROVIDER_DRIVER: ldap
STORAGE_LDAP_HOSTNAME: glauth STORAGE_LDAP_URI: "ldaps://glauth:9126"
STORAGE_LDAP_PORT: 9126
STORAGE_LDAP_INSECURE: "true" STORAGE_LDAP_INSECURE: "true"
STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva} STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva}
STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test} STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test}
@@ -53,26 +53,21 @@ services:
- /entrypoint-override.sh - /entrypoint-override.sh
environment: environment:
# CS3 users from ldap specific configuration # CS3 users from ldap specific configuration
IDP_LDAP_FILTER: "(&(objectclass=inetOrgPerson)(objectClass=owncloud))" LDAP_URI: ldaps://ldap-server
IDP_LDAP_URI: ldap://ldap-server:389 LDAP_INSECURE: "true"
IDP_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com" LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com"
IDP_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin} LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
IDP_LDAP_BASE_DN: "dc=owncloud,dc=com" LDAP_GROUP_BASE_DN: "dc=owncloud,dc=com"
IDP_LDAP_LOGIN_ATTRIBUTE: uid LDAP_GROUPFILTER: "(objectclass=owncloud)"
LDAP_GROUP_OBJECTCLASS: "groupOfUniqueNames"
LDAP_USER_BASE_DN: "dc=owncloud,dc=com"
LDAP_USERFILTER: "(objectclass=owncloud)"
LDAP_USER_OBEJECTCLASS: "inetOrgPerson"
LDAP_LOGIN_ATTRIBUTES: "uid,mail"
IDP_LDAP_LOGIN_ATTRIBUTE: "uid"
IDP_LDAP_UUID_ATTRIBUTE: "ownclouduuid" IDP_LDAP_UUID_ATTRIBUTE: "ownclouduuid"
IDP_LDAP_UUID_ATTRIBUTE_TYPE: binary IDP_LDAP_UUID_ATTRIBUTE_TYPE: binary
PROXY_ACCOUNT_BACKEND_TYPE: cs3 PROXY_ACCOUNT_BACKEND_TYPE: cs3
STORAGE_LDAP_HOSTNAME: ldap-server
STORAGE_LDAP_PORT: 636
STORAGE_LDAP_INSECURE: "true"
STORAGE_LDAP_BASE_DN: "dc=owncloud,dc=com"
STORAGE_LDAP_BIND_DN: "cn=admin,dc=owncloud,dc=com"
STORAGE_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
STORAGE_LDAP_LOGINFILTER: '(&(objectclass=inetOrgPerson)(objectclass=owncloud)(|(uid={{login}})(mail={{login}})))'
STORAGE_LDAP_USERFILTER: '(&(objectclass=inetOrgPerson)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))'
STORAGE_LDAP_ATTRIBUTEFILTER: '(&(objectclass=owncloud)({{attr}}={{value}}))'
STORAGE_LDAP_FINDFILTER: '(&(objectclass=owncloud)(|(uid={{query}}*)(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)(description={{query}}*)))'
STORAGE_LDAP_GROUPFILTER: '(&(objectclass=groupOfUniqueNames)(objectclass=owncloud)(ownclouduuid={{.OpaqueId}}*))'
# web ui # web ui
WEB_UI_CONFIG: "/var/tmp/ocis/.config/web-config.json" WEB_UI_CONFIG: "/var/tmp/ocis/.config/web-config.json"
# General oCIS config # General oCIS config
+2 -1
View File
@@ -22,7 +22,7 @@ require (
github.com/blevesearch/bleve/v2 v2.3.2 github.com/blevesearch/bleve/v2 v2.3.2
github.com/coreos/go-oidc/v3 v3.1.0 github.com/coreos/go-oidc/v3 v3.1.0
github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f github.com/cs3org/go-cs3apis v0.0.0-20220328105952-297bef33e13f
github.com/cs3org/reva/v2 v2.0.0-20220408142652-148b87297214 github.com/cs3org/reva/v2 v2.0.0-20220411161034-134ed5a0801f
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733
github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/chi/v5 v5.0.7
@@ -52,6 +52,7 @@ require (
github.com/oklog/run v1.1.0 github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.1.3
github.com/onsi/gomega v1.19.0 github.com/onsi/gomega v1.19.0
github.com/owncloud/libre-graph-api-go v0.13.3 github.com/owncloud/libre-graph-api-go v0.13.3
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
+2 -2
View File
@@ -335,8 +335,8 @@ github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3p
github.com/crewjam/saml v0.4.6 h1:XCUFPkQSJLvzyl4cW9OvpWUbRf0gE7VUpU8ZnilbeM4= github.com/crewjam/saml v0.4.6 h1:XCUFPkQSJLvzyl4cW9OvpWUbRf0gE7VUpU8ZnilbeM4=
github.com/crewjam/saml v0.4.6/go.mod h1:ZBOXnNPFzB3CgOkRm7Nd6IVdkG+l/wF+0ZXLqD96t1A= github.com/crewjam/saml v0.4.6/go.mod h1:ZBOXnNPFzB3CgOkRm7Nd6IVdkG+l/wF+0ZXLqD96t1A=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/reva/v2 v2.0.0-20220408142652-148b87297214 h1:8Akb8HGdilByInCNDEzwo2TSRTd7JNcHjU73Y3f6Yuo= github.com/cs3org/reva/v2 v2.0.0-20220411161034-134ed5a0801f h1:SNQSbtvhsQ6KvdDJlW536pUMq8RzghQMDCkYYKEFn8c=
github.com/cs3org/reva/v2 v2.0.0-20220408142652-148b87297214/go.mod h1:rE2wCGoiGiUuQ3zj6aD7sZ+BhboLyNsNQ3z3auunWm4= github.com/cs3org/reva/v2 v2.0.0-20220411161034-134ed5a0801f/go.mod h1:rE2wCGoiGiUuQ3zj6aD7sZ+BhboLyNsNQ3z3auunWm4=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
+17 -15
View File
@@ -37,26 +37,28 @@ type Spaces struct {
} }
type LDAP struct { type LDAP struct {
URI string `yaml:"uri" env:"GRAPH_LDAP_URI"` URI string `yaml:"uri" env:"LDAP_URI;GRAPH_LDAP_URI"`
Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;GRAPH_LDAP_INSECURE"` Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;GRAPH_LDAP_INSECURE"`
BindDN string `yaml:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` BindDN string `yaml:"bind_dn" env:"LDAP_BIND_DN;GRAPH_LDAP_BIND_DN"`
BindPassword string `yaml:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` BindPassword string `yaml:"bind_password" env:"LDAP_BIND_PASSWORD;GRAPH_LDAP_BIND_PASSWORD"`
UseServerUUID bool `yaml:"use_server_uuid" env:"GRAPH_LDAP_SERVER_UUID"` UseServerUUID bool `yaml:"use_server_uuid" env:"GRAPH_LDAP_SERVER_UUID"`
WriteEnabled bool `yaml:"write_enabled" env:"GRAPH_LDAP_SERVER_WRITE_ENABLED"` WriteEnabled bool `yaml:"write_enabled" env:"GRAPH_LDAP_SERVER_WRITE_ENABLED"`
UserBaseDN string `yaml:"user_base_dn" env:"GRAPH_LDAP_USER_BASE_DN"` UserBaseDN string `yaml:"user_base_dn" env:"LDAP_USER_BASE_DN;GRAPH_LDAP_USER_BASE_DN"`
UserSearchScope string `yaml:"user_search_scope" env:"GRAPH_LDAP_USER_SCOPE"` UserSearchScope string `yaml:"user_search_scope" env:"LDAP_USER_SCOPE;GRAPH_LDAP_USER_SCOPE"`
UserFilter string `yaml:"user_filter" env:"GRAPH_LDAP_USER_FILTER"` UserFilter string `yaml:"user_filter" env:"LDAP_USER_FILTER;GRAPH_LDAP_USER_FILTER"`
UserEmailAttribute string `yaml:"user_mail_attribute" env:"GRAPH_LDAP_USER_EMAIL_ATTRIBUTE"` UserObjectClass string `yaml:"user_objectclass" env:"LDAP_USER_OBJECTCLASS;GRAPH_LDAP_USER_OBJECTCLASS"`
UserDisplayNameAttribute string `yaml:"user_displayname_attribute" env:"GRAPH_LDAP_USER_DISPLAYNAME_ATTRIBUTE"` UserEmailAttribute string `yaml:"user_mail_attribute" env:"LDAP_USER_SCHEMA_MAIL;GRAPH_LDAP_USER_EMAIL_ATTRIBUTE"`
UserNameAttribute string `yaml:"user_name_attribute" env:"GRAPH_LDAP_USER_NAME_ATTRIBUTE"` UserDisplayNameAttribute string `yaml:"user_displayname_attribute" env:"LDAP_USER_SCHEMA_DISPLAY_NAME;GRAPH_LDAP_USER_DISPLAYNAME_ATTRIBUTE"`
UserIDAttribute string `yaml:"user_id_attribute" env:"GRAPH_LDAP_USER_UID_ATTRIBUTE"` UserNameAttribute string `yaml:"user_name_attribute" env:"LDAP_USER_SCHEMA_USERNAME;GRAPH_LDAP_USER_NAME_ATTRIBUTE"`
UserIDAttribute string `yaml:"user_id_attribute" env:"LDAP_USER_SCHEMA_ID;GRAPH_LDAP_USER_UID_ATTRIBUTE"`
GroupBaseDN string `yaml:"group_base_dn" env:"GRAPH_LDAP_GROUP_BASE_DN"` GroupBaseDN string `yaml:"group_base_dn" env:"LDAP_GROUP_BASE_DN;GRAPH_LDAP_GROUP_BASE_DN"`
GroupSearchScope string `yaml:"group_search_scope" env:"GRAPH_LDAP_GROUP_SEARCH_SCOPE"` GroupSearchScope string `yaml:"group_search_scope" env:"LDAP_GROUP_SCOPE;GRAPH_LDAP_GROUP_SEARCH_SCOPE"`
GroupFilter string `yaml:"group_filter" env:"GRAPH_LDAP_GROUP_FILTER"` GroupFilter string `yaml:"group_filter" env:"LDAP_GROUP_FILTER;GRAPH_LDAP_GROUP_FILTER"`
GroupNameAttribute string `yaml:"group_name_attribute" env:"GRAPH_LDAP_GROUP_NAME_ATTRIBUTE"` GroupObjectClass string `yaml:"group_objectclass" env:"LDAP_GROUP_OBJECTCLASS;GRAPH_LDAP_GROUP_OBJECTCLASS"`
GroupIDAttribute string `yaml:"group_id_attribute" env:"GRAPH_LDAP_GROUP_ID_ATTRIBUTE"` GroupNameAttribute string `yaml:"group_name_attribute" env:"LDAP_GROUP_SCHEMA_GROUPNAME;GRAPH_LDAP_GROUP_NAME_ATTRIBUTE"`
GroupIDAttribute string `yaml:"group_id_attribute" env:"LDAP_GROUP_SCHEMA_ID;GRAPH_LDAP_GROUP_ID_ATTRIBUTE"`
} }
type Identity struct { type Identity struct {
+4 -2
View File
@@ -43,7 +43,8 @@ func DefaultConfig() *config.Config {
WriteEnabled: false, WriteEnabled: false,
UserBaseDN: "ou=users,dc=ocis,dc=test", UserBaseDN: "ou=users,dc=ocis,dc=test",
UserSearchScope: "sub", UserSearchScope: "sub",
UserFilter: "(objectClass=inetOrgPerson)", UserFilter: "",
UserObjectClass: "inetOrgPerson",
UserEmailAttribute: "mail", UserEmailAttribute: "mail",
UserDisplayNameAttribute: "displayName", UserDisplayNameAttribute: "displayName",
UserNameAttribute: "uid", UserNameAttribute: "uid",
@@ -52,7 +53,8 @@ func DefaultConfig() *config.Config {
UserIDAttribute: "owncloudUUID", UserIDAttribute: "owncloudUUID",
GroupBaseDN: "ou=groups,dc=ocis,dc=test", GroupBaseDN: "ou=groups,dc=ocis,dc=test",
GroupSearchScope: "sub", GroupSearchScope: "sub",
GroupFilter: "(objectclass=groupOfNames)", GroupFilter: "",
GroupObjectClass: "groupOfNames",
GroupNameAttribute: "cn", GroupNameAttribute: "cn",
GroupIDAttribute: "owncloudUUID", GroupIDAttribute: "owncloudUUID",
}, },
+9 -5
View File
@@ -27,11 +27,13 @@ type LDAP struct {
userBaseDN string userBaseDN string
userFilter string userFilter string
userObjectClass string
userScope int userScope int
userAttributeMap userAttributeMap userAttributeMap userAttributeMap
groupBaseDN string groupBaseDN string
groupFilter string groupFilter string
groupObjectClass string
groupScope int groupScope int
groupAttributeMap groupAttributeMap groupAttributeMap groupAttributeMap
@@ -89,10 +91,12 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD
useServerUUID: config.UseServerUUID, useServerUUID: config.UseServerUUID,
userBaseDN: config.UserBaseDN, userBaseDN: config.UserBaseDN,
userFilter: config.UserFilter, userFilter: config.UserFilter,
userObjectClass: config.UserObjectClass,
userScope: userScope, userScope: userScope,
userAttributeMap: uam, userAttributeMap: uam,
groupBaseDN: config.GroupBaseDN, groupBaseDN: config.GroupBaseDN,
groupFilter: config.GroupFilter, groupFilter: config.GroupFilter,
groupObjectClass: config.GroupObjectClass,
groupScope: groupScope, groupScope: groupScope,
groupAttributeMap: gam, groupAttributeMap: gam,
logger: logger, logger: logger,
@@ -311,7 +315,7 @@ func (i *LDAP) getLDAPUserByNameOrID(nameOrID string) (*ldap.Entry, error) {
func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) { func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) {
searchRequest := ldap.NewSearchRequest( searchRequest := ldap.NewSearchRequest(
i.userBaseDN, i.userScope, ldap.NeverDerefAliases, 1, 0, false, i.userBaseDN, i.userScope, ldap.NeverDerefAliases, 1, 0, false,
fmt.Sprintf("(&%s%s)", i.userFilter, filter), fmt.Sprintf("(&%s(objectClass=%s)%s)", i.userFilter, i.userObjectClass, filter),
[]string{ []string{
i.userAttributeMap.displayName, i.userAttributeMap.displayName,
i.userAttributeMap.id, i.userAttributeMap.id,
@@ -357,7 +361,7 @@ func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregra
if search == "" { if search == "" {
search = queryParam.Get("$search") search = queryParam.Get("$search")
} }
userFilter := i.userFilter userFilter := fmt.Sprintf("%s(objectClass=%s)", i.userFilter, i.userObjectClass)
if search != "" { if search != "" {
search = ldap.EscapeFilter(search) search = ldap.EscapeFilter(search)
userFilter = fmt.Sprintf( userFilter = fmt.Sprintf(
@@ -428,7 +432,7 @@ func (i *LDAP) getLDAPGroupByFilter(filter string, requestMembers bool) (*ldap.E
// Search for LDAP Groups matching the specified filter, if requestMembers is true the groupMemberShip // Search for LDAP Groups matching the specified filter, if requestMembers is true the groupMemberShip
// attribute will be part of the result attributes. The LDAP filter is combined with the configured groupFilter // attribute will be part of the result attributes. The LDAP filter is combined with the configured groupFilter
// resulting in a filter like "(&(LDAP.groupFilter)(<filter_from_args>))" // resulting in a filter like "(&(LDAP.groupFilter)(objectClass=LDAP.groupObjectClass)(<filter_from_args>))"
func (i *LDAP) getLDAPGroupsByFilter(filter string, requestMembers, single bool) ([]*ldap.Entry, error) { func (i *LDAP) getLDAPGroupsByFilter(filter string, requestMembers, single bool) ([]*ldap.Entry, error) {
attrs := []string{ attrs := []string{
i.groupAttributeMap.name, i.groupAttributeMap.name,
@@ -445,7 +449,7 @@ func (i *LDAP) getLDAPGroupsByFilter(filter string, requestMembers, single bool)
} }
searchRequest := ldap.NewSearchRequest( searchRequest := ldap.NewSearchRequest(
i.groupBaseDN, i.groupScope, ldap.NeverDerefAliases, sizelimit, 0, false, i.groupBaseDN, i.groupScope, ldap.NeverDerefAliases, sizelimit, 0, false,
fmt.Sprintf("(&%s%s)", i.groupFilter, filter), fmt.Sprintf("(&%s(objectClass=%s)%s)", i.groupFilter, i.groupObjectClass, filter),
attrs, attrs,
nil, nil,
) )
@@ -511,7 +515,7 @@ func (i *LDAP) GetGroups(ctx context.Context, queryParam url.Values) ([]*libregr
if search == "" { if search == "" {
search = queryParam.Get("$search") search = queryParam.Get("$search")
} }
groupFilter := i.groupFilter groupFilter := fmt.Sprintf("%s(objectClass=%s)", i.groupFilter, i.groupObjectClass)
if search != "" { if search != "" {
search = ldap.EscapeFilter(search) search = ldap.EscapeFilter(search)
groupFilter = fmt.Sprintf( groupFilter = fmt.Sprintf(
+10 -9
View File
@@ -27,21 +27,22 @@ type Config struct {
// Ldap defines the available LDAP configuration. // Ldap defines the available LDAP configuration.
type Ldap struct { type Ldap struct {
URI string `yaml:"uri" env:"IDP_LDAP_URI"` URI string `yaml:"uri" env:"LDAP_URI;IDP_LDAP_URI"`
BindDN string `yaml:"bind_dn" env:"IDP_LDAP_BIND_DN"` BindDN string `yaml:"bind_dn" env:"LDAP_BIND_DN;IDP_LDAP_BIND_DN"`
BindPassword string `yaml:"bind_password" env:"IDP_LDAP_BIND_PASSWORD"` BindPassword string `yaml:"bind_password" env:"LDAP_BIND_PASSWORD;IDP_LDAP_BIND_PASSWORD"`
BaseDN string `yaml:"base_dn" env:"IDP_LDAP_BASE_DN"` BaseDN string `yaml:"base_dn" env:"LDAP_USER_BASE_DN,IDP_LDAP_BASE_DN"`
Scope string `yaml:"scope" env:"IDP_LDAP_SCOPE"` Scope string `yaml:"scope" env:"LDAP_USER_SCOPE;IDP_LDAP_SCOPE"`
LoginAttribute string `yaml:"login_attribute" env:"IDP_LDAP_LOGIN_ATTRIBUTE"` LoginAttribute string `yaml:"login_attribute" env:"IDP_LDAP_LOGIN_ATTRIBUTE"`
EmailAttribute string `yaml:"email_attribute" env:"IDP_LDAP_EMAIL_ATTRIBUTE"` EmailAttribute string `yaml:"email_attribute" env:"LDAP_USER_SCHEMA_MAIL;IDP_LDAP_EMAIL_ATTRIBUTE"`
NameAttribute string `yaml:"name_attribute" env:"IDP_LDAP_NAME_ATTRIBUTE"` NameAttribute string `yaml:"name_attribute" env:"LDAP_USER_SCHEMA_USERNAME;IDP_LDAP_NAME_ATTRIBUTE"`
UUIDAttribute string `yaml:"uuid_attribute" env:"IDP_LDAP_UUID_ATTRIBUTE"` UUIDAttribute string `yaml:"uuid_attribute" env:"LDAP_USER_SCHEMA_ID;IDP_LDAP_UUID_ATTRIBUTE"`
UUIDAttributeType string `yaml:"uuid_attribute_type" env:"IDP_LDAP_UUID_ATTRIBUTE_TYPE"` UUIDAttributeType string `yaml:"uuid_attribute_type" env:"IDP_LDAP_UUID_ATTRIBUTE_TYPE"`
Filter string `yaml:"filter" env:"IDP_LDAP_FILTER"` Filter string `yaml:"filter" env:"LDAP_USER_FILTER;IDP_LDAP_FILTER"`
ObjectClass string `yaml:"objectclass" env:"LDAP_USER_OBJECTCLASS;IDP_LDAP_OBJECTCLASS"`
} }
// Asset defines the available asset configuration. // Asset defines the available asset configuration.
+3 -2
View File
@@ -75,10 +75,11 @@ func DefaultConfig() *config.Config {
Scope: "sub", Scope: "sub",
LoginAttribute: "cn", LoginAttribute: "cn",
EmailAttribute: "mail", EmailAttribute: "mail",
NameAttribute: "sn", NameAttribute: "displayName",
UUIDAttribute: "uid", UUIDAttribute: "uid",
UUIDAttributeType: "text", UUIDAttributeType: "text",
Filter: "(objectClass=posixaccount)", Filter: "",
ObjectClass: "posixAccount",
}, },
} }
} }
+5 -1
View File
@@ -124,6 +124,10 @@ func createConfigsIfNotExist(assets http.FileSystem, filePath, ocisURL string) e
// Init vars which are currently not accessible via idp api // Init vars which are currently not accessible via idp api
func initLicoInternalEnvVars(ldap *config.Ldap) error { func initLicoInternalEnvVars(ldap *config.Ldap) error {
filter := fmt.Sprintf("(objectclass=%s)", ldap.ObjectClass)
if ldap.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", ldap.Filter, filter)
}
var defaults = map[string]string{ var defaults = map[string]string{
"LDAP_URI": ldap.URI, "LDAP_URI": ldap.URI,
"LDAP_BINDDN": ldap.BindDN, "LDAP_BINDDN": ldap.BindDN,
@@ -135,7 +139,7 @@ func initLicoInternalEnvVars(ldap *config.Ldap) error {
"LDAP_NAME_ATTRIBUTE": ldap.NameAttribute, "LDAP_NAME_ATTRIBUTE": ldap.NameAttribute,
"LDAP_UUID_ATTRIBUTE": ldap.UUIDAttribute, "LDAP_UUID_ATTRIBUTE": ldap.UUIDAttribute,
"LDAP_UUID_ATTRIBUTE_TYPE": ldap.UUIDAttributeType, "LDAP_UUID_ATTRIBUTE_TYPE": ldap.UUIDAttributeType,
"LDAP_FILTER": ldap.Filter, "LDAP_FILTER": filter,
} }
for k, v := range defaults { for k, v := range defaults {
+13
View File
@@ -0,0 +1,13 @@
package config_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestConfig(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Config Suite")
}
+11 -12
View File
@@ -1,17 +1,16 @@
package config package config_test
import ( import (
"fmt" . "github.com/onsi/ginkgo/v2"
"testing" . "github.com/onsi/gomega"
"github.com/owncloud/ocis/ocis-pkg/config"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
func TestDefaultConfig(t *testing.T) { var _ = Describe("Config", func() {
cfg := DefaultConfig() It("Success generating the default config", func() {
yBytes, err := yaml.Marshal(cfg) cfg := config.DefaultConfig()
if err != nil { _, err := yaml.Marshal(cfg)
panic(err) Expect(err).To(BeNil())
} })
fmt.Println(string(yBytes)) })
}
+14
View File
@@ -3,6 +3,7 @@ package config
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
gofig "github.com/gookit/config/v2" gofig "github.com/gookit/config/v2"
"github.com/owncloud/ocis/ocis-pkg/shared" "github.com/owncloud/ocis/ocis-pkg/shared"
@@ -35,6 +36,11 @@ func bindEnv(c *gofig.Config, bindings []shared.EnvBinding) error {
// defaults to float64 // defaults to float64
r := c.Float(bindings[i].EnvVars[j]) r := c.Float(bindings[i].EnvVars[j])
*bindings[i].Destination.(*float64) = r *bindings[i].Destination.(*float64) = r
case "*[]string":
// Treat values a comma-separated list
r := c.String(bindings[i].EnvVars[j])
vals := envStringToSlice(r)
*bindings[i].Destination.(*[]string) = vals
default: default:
// it is unlikely we will ever get here. Let this serve more as a runtime check for when debugging. // it is unlikely we will ever get here. Let this serve more as a runtime check for when debugging.
return fmt.Errorf("invalid type for env var: `%v`", bindings[i].EnvVars[j]) return fmt.Errorf("invalid type for env var: `%v`", bindings[i].EnvVars[j])
@@ -45,3 +51,11 @@ func bindEnv(c *gofig.Config, bindings []shared.EnvBinding) error {
return nil return nil
} }
func envStringToSlice(value string) []string {
vals := strings.Split(value, ",")
for i := range vals {
vals[i] = strings.TrimSpace(vals[i])
}
return vals
}
+35
View File
@@ -0,0 +1,35 @@
package config_test
import (
gofig "github.com/gookit/config/v2"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
var _ = Describe("Environment", func() {
It("Succeed to parse a comma separated list in to a sting slice", func() {
cfg := gofig.NewEmpty("test")
err := cfg.Set("stringlist", "one,two,three")
Expect(err).To(Not(HaveOccurred()))
err = cfg.Set("stringlist2", "one ,two , t h r e e")
Expect(err).To(Not(HaveOccurred()))
var stringTest, stringTest2 []string
eb := []shared.EnvBinding{
{
EnvVars: []string{"stringlist"},
Destination: &stringTest,
},
{
EnvVars: []string{"stringlist2"},
Destination: &stringTest2,
},
}
err = ociscfg.BindEnv(cfg, eb)
Expect(err).To(Not(HaveOccurred()))
Expect(stringTest).To(Equal([]string{"one", "two", "three"}))
Expect(stringTest2).To(Equal([]string{"one", "two", "t h r e e"}))
})
})
+8 -19
View File
@@ -50,6 +50,13 @@ func AuthBasic(cfg *config.Config) *cli.Command {
Interface("reva-config", rcfg). Interface("reva-config", rcfg).
Msg("config") Msg("config")
if cfg.Reva.AuthProvider.Driver == "ldap" {
if err := waitForLDAPCA(logger, &cfg.Reva.LDAP); err != nil {
logger.Error().Err(err).Msg("The configured LDAP CA cert does not exist")
return err
}
}
gr.Add(func() error { gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger)) runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil return nil
@@ -113,25 +120,7 @@ func authBasicConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]in
"json": map[string]interface{}{ "json": map[string]interface{}{
"users": cfg.Reva.AuthProvider.JSON, "users": cfg.Reva.AuthProvider.JSON,
}, },
"ldap": map[string]interface{}{ "ldap": ldapConfigFromString(cfg),
"hostname": cfg.Reva.LDAP.Hostname,
"port": cfg.Reva.LDAP.Port,
"cacert": cfg.Reva.LDAP.CACert,
"insecure": cfg.Reva.LDAP.Insecure,
"base_dn": cfg.Reva.LDAP.BaseDN,
"loginfilter": cfg.Reva.LDAP.LoginFilter,
"bind_username": cfg.Reva.LDAP.BindDN,
"bind_password": cfg.Reva.LDAP.BindPassword,
"idp": cfg.Reva.LDAP.IDP,
"gatewaysvc": cfg.Reva.Gateway.Endpoint,
"schema": map[string]interface{}{
"dn": "dn",
"uid": cfg.Reva.LDAP.UserSchema.UID,
"mail": cfg.Reva.LDAP.UserSchema.Mail,
"displayName": cfg.Reva.LDAP.UserSchema.DisplayName,
"cn": cfg.Reva.LDAP.UserSchema.CN,
},
},
"owncloudsql": map[string]interface{}{ "owncloudsql": map[string]interface{}{
"dbusername": cfg.Reva.UserOwnCloudSQL.DBUsername, "dbusername": cfg.Reva.UserOwnCloudSQL.DBUsername,
"dbpassword": cfg.Reva.UserOwnCloudSQL.DBPassword, "dbpassword": cfg.Reva.UserOwnCloudSQL.DBPassword,
+8 -22
View File
@@ -46,6 +46,13 @@ func Groups(cfg *config.Config) *cli.Command {
rcfg := groupsConfigFromStruct(c, cfg) rcfg := groupsConfigFromStruct(c, cfg)
if cfg.Reva.Groups.Driver == "ldap" {
if err := waitForLDAPCA(logger, &cfg.Reva.LDAP); err != nil {
logger.Error().Err(err).Msg("The configured LDAP CA cert does not exist")
return err
}
}
gr.Add(func() error { gr.Add(func() error {
runtime.RunWithOptions( runtime.RunWithOptions(
rcfg, rcfg,
@@ -113,28 +120,7 @@ func groupsConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]inter
"json": map[string]interface{}{ "json": map[string]interface{}{
"groups": cfg.Reva.Groups.JSON, "groups": cfg.Reva.Groups.JSON,
}, },
"ldap": map[string]interface{}{ "ldap": ldapConfigFromString(cfg),
"hostname": cfg.Reva.LDAP.Hostname,
"port": cfg.Reva.LDAP.Port,
"cacert": cfg.Reva.LDAP.CACert,
"insecure": cfg.Reva.LDAP.Insecure,
"base_dn": cfg.Reva.LDAP.BaseDN,
"groupfilter": cfg.Reva.LDAP.GroupFilter,
"attributefilter": cfg.Reva.LDAP.GroupAttributeFilter,
"findfilter": cfg.Reva.LDAP.GroupFindFilter,
"memberfilter": cfg.Reva.LDAP.GroupMemberFilter,
"bind_username": cfg.Reva.LDAP.BindDN,
"bind_password": cfg.Reva.LDAP.BindPassword,
"idp": cfg.Reva.LDAP.IDP,
"schema": map[string]interface{}{
"dn": "dn",
"gid": cfg.Reva.LDAP.GroupSchema.GID,
"mail": cfg.Reva.LDAP.GroupSchema.Mail,
"displayName": cfg.Reva.LDAP.GroupSchema.DisplayName,
"cn": cfg.Reva.LDAP.GroupSchema.CN,
"gidNumber": cfg.Reva.LDAP.GroupSchema.GIDNumber,
},
},
"rest": map[string]interface{}{ "rest": map[string]interface{}{
"client_id": cfg.Reva.UserGroupRest.ClientID, "client_id": cfg.Reva.UserGroupRest.ClientID,
"client_secret": cfg.Reva.UserGroupRest.ClientSecret, "client_secret": cfg.Reva.UserGroupRest.ClientSecret,
+60
View File
@@ -0,0 +1,60 @@
package command
import (
"errors"
"os"
"time"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/storage/pkg/config"
)
const caTimeout = 5
func ldapConfigFromString(cfg *config.Config) map[string]interface{} {
return map[string]interface{}{
"uri": cfg.Reva.LDAP.URI,
"cacert": cfg.Reva.LDAP.CACert,
"insecure": cfg.Reva.LDAP.Insecure,
"bind_username": cfg.Reva.LDAP.BindDN,
"bind_password": cfg.Reva.LDAP.BindPassword,
"user_base_dn": cfg.Reva.LDAP.UserBaseDN,
"group_base_dn": cfg.Reva.LDAP.GroupBaseDN,
"user_filter": cfg.Reva.LDAP.UserFilter,
"group_filter": cfg.Reva.LDAP.GroupFilter,
"user_objectclass": cfg.Reva.LDAP.UserObjectClass,
"group_objectclass": cfg.Reva.LDAP.GroupObjectClass,
"login_attributes": cfg.Reva.LDAP.LoginAttributes,
"idp": cfg.Reva.LDAP.IDP,
"gatewaysvc": cfg.Reva.Gateway.Endpoint,
"user_schema": map[string]interface{}{
"id": cfg.Reva.LDAP.UserSchema.ID,
"idIsOctetString": cfg.Reva.LDAP.UserSchema.IDIsOctetString,
"mail": cfg.Reva.LDAP.UserSchema.Mail,
"displayName": cfg.Reva.LDAP.UserSchema.DisplayName,
"userName": cfg.Reva.LDAP.UserSchema.Username,
},
"group_schema": map[string]interface{}{
"id": cfg.Reva.LDAP.GroupSchema.ID,
"idIsOctetString": cfg.Reva.LDAP.GroupSchema.IDIsOctetString,
"mail": cfg.Reva.LDAP.GroupSchema.Mail,
"displayName": cfg.Reva.LDAP.GroupSchema.DisplayName,
"groupName": cfg.Reva.LDAP.GroupSchema.Groupname,
"member": cfg.Reva.LDAP.GroupSchema.Member,
},
}
}
func waitForLDAPCA(log log.Logger, cfg *config.LDAP) error {
if !cfg.Insecure && cfg.CACert != "" {
if _, err := os.Stat(cfg.CACert); errors.Is(err, os.ErrNotExist) {
log.Warn().Str("LDAP CACert", cfg.CACert).Msgf("File does not exist. Waiting %d seconds for it to appear.", caTimeout)
time.Sleep(caTimeout * time.Second)
if _, err := os.Stat(cfg.CACert); errors.Is(err, os.ErrNotExist) {
log.Warn().Str("LDAP CACert", cfg.CACert).Msgf("File does still not exist after Timeout")
return err
}
}
}
return nil
}
+9 -23
View File
@@ -48,11 +48,19 @@ func Users(cfg *config.Config) *cli.Command {
pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid") pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")
rcfg := usersConfigFromStruct(c, cfg) rcfg := usersConfigFromStruct(c, cfg)
logger.Debug(). logger.Debug().
Str("server", "users"). Str("server", "users").
Interface("reva-config", rcfg). Interface("reva-config", rcfg).
Msg("config") Msg("config")
if cfg.Reva.Users.Driver == "ldap" {
if err := waitForLDAPCA(logger, &cfg.Reva.LDAP); err != nil {
logger.Error().Err(err).Msg("The configured LDAP CA cert does not exist")
return err
}
}
gr.Add(func() error { gr.Add(func() error {
runtime.RunWithOptions( runtime.RunWithOptions(
rcfg, rcfg,
@@ -120,29 +128,7 @@ func usersConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]interf
"json": map[string]interface{}{ "json": map[string]interface{}{
"users": cfg.Reva.Users.JSON, "users": cfg.Reva.Users.JSON,
}, },
"ldap": map[string]interface{}{ "ldap": ldapConfigFromString(cfg),
"hostname": cfg.Reva.LDAP.Hostname,
"port": cfg.Reva.LDAP.Port,
"cacert": cfg.Reva.LDAP.CACert,
"insecure": cfg.Reva.LDAP.Insecure,
"base_dn": cfg.Reva.LDAP.BaseDN,
"userfilter": cfg.Reva.LDAP.UserFilter,
"attributefilter": cfg.Reva.LDAP.UserAttributeFilter,
"findfilter": cfg.Reva.LDAP.UserFindFilter,
"groupfilter": cfg.Reva.LDAP.UserGroupFilter,
"bind_username": cfg.Reva.LDAP.BindDN,
"bind_password": cfg.Reva.LDAP.BindPassword,
"idp": cfg.Reva.LDAP.IDP,
"schema": map[string]interface{}{
"dn": "dn",
"uid": cfg.Reva.LDAP.UserSchema.UID,
"mail": cfg.Reva.LDAP.UserSchema.Mail,
"displayName": cfg.Reva.LDAP.UserSchema.DisplayName,
"cn": cfg.Reva.LDAP.UserSchema.CN,
"uidNumber": cfg.Reva.LDAP.UserSchema.UIDNumber,
"gidNumber": cfg.Reva.LDAP.UserSchema.GIDNumber,
},
},
"rest": map[string]interface{}{ "rest": map[string]interface{}{
"client_id": cfg.Reva.UserGroupRest.ClientID, "client_id": cfg.Reva.UserGroupRest.ClientID,
"client_secret": cfg.Reva.UserGroupRest.ClientSecret, "client_secret": cfg.Reva.UserGroupRest.ClientSecret,
+90 -85
View File
@@ -363,25 +363,23 @@ type OIDC struct {
// LDAP defines the available ldap configuration. // LDAP defines the available ldap configuration.
type LDAP struct { type LDAP struct {
Hostname string `yaml:"hostname"` URI string `yaml:"uri"`
Port int `yaml:"port"` CACert string `yaml:"ca_cert"`
CACert string `yaml:"ca_cert"` Insecure bool `yaml:"insecure"`
Insecure bool `yaml:"insecure"` UserBaseDN string `yaml:"user_base_dn"`
BaseDN string `yaml:"base_dn"` GroupBaseDN string `yaml:"group_base_dn"`
LoginFilter string `yaml:"login_filter"` UserScope string `yaml:"user_scope"`
UserFilter string `yaml:"user_filter"` GroupScope string `yaml:"group_scope"`
UserAttributeFilter string `yaml:"user_attribute_filter"` UserObjectClass string `yaml:"user_objectclass"`
UserFindFilter string `yaml:"user_find_filter"` GroupObjectClass string `yaml:"group_objectclass"`
UserGroupFilter string `yaml:"user_group_filter"` UserFilter string `yaml:"user_filter"`
GroupFilter string `yaml:"group_filter"` GroupFilter string `yaml:"group_filter"`
GroupAttributeFilter string `yaml:"group_attribute_filter"` LoginAttributes []string `yaml:"login_attributes"`
GroupFindFilter string `yaml:"group_finder_filter"` BindDN string `yaml:"bind_dn"`
GroupMemberFilter string `yaml:"group_member_filter"` BindPassword string `yaml:"bind_password"`
BindDN string `yaml:"bind_dn"` IDP string `yaml:"idp"`
BindPassword string `yaml:"bind_password"` UserSchema LDAPUserSchema `yaml:"user_schema"`
IDP string `yaml:"idp"` GroupSchema LDAPGroupSchema `yaml:"group_schema"`
UserSchema LDAPUserSchema `yaml:"user_schema"`
GroupSchema LDAPGroupSchema `yaml:"group_schema"`
} }
// UserGroupRest defines the REST driver specification for user and group resolution. // UserGroupRest defines the REST driver specification for user and group resolution.
@@ -413,21 +411,24 @@ type UserOwnCloudSQL struct {
// LDAPUserSchema defines the available ldap user schema configuration. // LDAPUserSchema defines the available ldap user schema configuration.
type LDAPUserSchema struct { type LDAPUserSchema struct {
UID string `yaml:"uid"` ID string `yaml:"id"`
Mail string `yaml:"mail"` IDIsOctetString bool `yaml:"id_is_octet_string"`
DisplayName string `yaml:"display_name"` Mail string `yaml:"mail"`
CN string `yaml:"cn"` DisplayName string `yaml:"display_name"`
UIDNumber string `yaml:"uid_number"` Username string `yaml:"user_name"`
GIDNumber string `yaml:"gid_number"` UIDNumber string `yaml:"uid_number"`
GIDNumber string `yaml:"gid_number"`
} }
// LDAPGroupSchema defines the available ldap group schema configuration. // LDAPGroupSchema defines the available ldap group schema configuration.
type LDAPGroupSchema struct { type LDAPGroupSchema struct {
GID string `yaml:"gid"` ID string `yaml:"id"`
Mail string `yaml:"mail"` IDIsOctetString bool `yaml:"id_is_octet_string"`
DisplayName string `yaml:"display_name"` Mail string `yaml:"mail"`
CN string `yaml:"cn"` DisplayName string `yaml:"display_name"`
GIDNumber string `yaml:"gid_number"` Groupname string `yaml:"group_name"`
Member string `yaml:"member"`
GIDNumber string `yaml:"gid_number"`
} }
// OCDav defines the available ocdav configuration. // OCDav defines the available ocdav configuration.
@@ -1020,111 +1021,115 @@ func structMappings(cfg *Config) []shared.EnvBinding {
// ldap // ldap
{ {
EnvVars: []string{"STORAGE_LDAP_HOSTNAME"}, EnvVars: []string{"LDAP_URI", "STORAGE_LDAP_URI"},
Destination: &cfg.Reva.LDAP.Hostname, Destination: &cfg.Reva.LDAP.URI,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_PORT"}, EnvVars: []string{"LDAP_CACERT", "STORAGE_LDAP_CACERT"},
Destination: &cfg.Reva.LDAP.Port,
},
{
EnvVars: []string{"STORAGE_LDAP_CACERT"},
Destination: &cfg.Reva.LDAP.CACert, Destination: &cfg.Reva.LDAP.CACert,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_INSECURE"}, EnvVars: []string{"LDAP_INSECURE", "STORAGE_LDAP_INSECURE"},
Destination: &cfg.Reva.LDAP.Insecure, Destination: &cfg.Reva.LDAP.Insecure,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_BASE_DN"}, EnvVars: []string{"LDAP_USER_BASE_DN", "STORAGE_LDAP_USER_BASE_DN"},
Destination: &cfg.Reva.LDAP.BaseDN, Destination: &cfg.Reva.LDAP.UserBaseDN,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_LOGINFILTER"}, EnvVars: []string{"LDAP_GROUP_BASE_DN", "STORAGE_LDAP_GROUP_BASE_DN"},
Destination: &cfg.Reva.LDAP.LoginFilter, Destination: &cfg.Reva.LDAP.GroupBaseDN,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USERFILTER"}, EnvVars: []string{"LDAP_USER_SCOPE", "STORAGE_LDAP_USER_SCOPE"},
Destination: &cfg.Reva.LDAP.UserScope,
},
{
EnvVars: []string{"LDAP_GROUP_SCOPE", "STORAGE_LDAP_GROUP_SCOPE"},
Destination: &cfg.Reva.LDAP.GroupScope,
},
{
EnvVars: []string{"LDAP_USER_OBJECTCLASS", "STORAGE_LDAP_USER_OBJECTCLASS"},
Destination: &cfg.Reva.LDAP.UserObjectClass,
},
{
EnvVars: []string{"LDAP_GROUP_OBJECTCLASS", "STORAGE_LDAP_GROUP_OBJECTCLASS"},
Destination: &cfg.Reva.LDAP.GroupObjectClass,
},
{
EnvVars: []string{"LDAP_LOGIN_ATTRIBUTES", "STORAGE_LDAP_LOGIN_ATTRIBUTES"},
Destination: &cfg.Reva.LDAP.LoginAttributes,
},
{
EnvVars: []string{"LDAP_USERFILTER", "STORAGE_LDAP_USERFILTER"},
Destination: &cfg.Reva.LDAP.UserFilter, Destination: &cfg.Reva.LDAP.UserFilter,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USERATTRIBUTEFILTER"}, EnvVars: []string{"LDAP_GROUPFILTER", "STORAGE_LDAP_GROUPFILTER"},
Destination: &cfg.Reva.LDAP.UserAttributeFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_USERFINDFILTER"},
Destination: &cfg.Reva.LDAP.UserFindFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_USERGROUPFILTER"},
Destination: &cfg.Reva.LDAP.UserGroupFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_GROUPFILTER"},
Destination: &cfg.Reva.LDAP.GroupFilter, Destination: &cfg.Reva.LDAP.GroupFilter,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUPATTRIBUTEFILTER"}, EnvVars: []string{"LDAP_BIND_DN", "STORAGE_LDAP_BIND_DN"},
Destination: &cfg.Reva.LDAP.GroupAttributeFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_GROUPFINDFILTER"},
Destination: &cfg.Reva.LDAP.GroupFindFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_GROUPMEMBERFILTER"},
Destination: &cfg.Reva.LDAP.GroupMemberFilter,
},
{
EnvVars: []string{"STORAGE_LDAP_BIND_DN"},
Destination: &cfg.Reva.LDAP.BindDN, Destination: &cfg.Reva.LDAP.BindDN,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_BIND_PASSWORD"}, EnvVars: []string{"LDAP_BIND_PASSWORD", "STORAGE_LDAP_BIND_PASSWORD"},
Destination: &cfg.Reva.LDAP.BindPassword, Destination: &cfg.Reva.LDAP.BindPassword,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_UID"}, EnvVars: []string{"LDAP_USER_SCHEMA_ID", "STORAGE_LDAP_USER_SCHEMA_ID"},
Destination: &cfg.Reva.LDAP.UserSchema.UID, Destination: &cfg.Reva.LDAP.UserSchema.ID,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_MAIL"}, EnvVars: []string{"LDAP_USER_SCHEMA_ID_IS_OCTETSTRING", "STORAGE_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING"},
Destination: &cfg.Reva.LDAP.UserSchema.IDIsOctetString,
},
{
EnvVars: []string{"LDAP_USER_SCHEMA_MAIL", "STORAGE_LDAP_USER_SCHEMA_MAIL"},
Destination: &cfg.Reva.LDAP.UserSchema.Mail, Destination: &cfg.Reva.LDAP.UserSchema.Mail,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME"}, EnvVars: []string{"LDAP_USER_SCHEMA_DISPLAYNAME", "STORAGE_LDAP_USER_SCHEMA_DISPLAYNAME"},
Destination: &cfg.Reva.LDAP.UserSchema.DisplayName, Destination: &cfg.Reva.LDAP.UserSchema.DisplayName,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_CN"}, EnvVars: []string{"LDAP_USER_SCHEMA_USERNAME", "STORAGE_LDAP_USER_SCHEMA_USERNAME"},
Destination: &cfg.Reva.LDAP.UserSchema.CN, Destination: &cfg.Reva.LDAP.UserSchema.Username,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_UID_NUMBER"}, EnvVars: []string{"LDAP_USER_SCHEMA_UID_NUMBER", "STORAGE_LDAP_USER_SCHEMA_UID_NUMBER"},
Destination: &cfg.Reva.LDAP.UserSchema.UIDNumber, Destination: &cfg.Reva.LDAP.UserSchema.UIDNumber,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_USER_SCHEMA_GID_NUMBER"}, EnvVars: []string{"LDAP_USER_SCHEMA_GID_NUMBER", "STORAGE_LDAP_USER_SCHEMA_GID_NUMBER"},
Destination: &cfg.Reva.LDAP.UserSchema.GIDNumber, Destination: &cfg.Reva.LDAP.UserSchema.GIDNumber,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUP_SCHEMA_GID"}, EnvVars: []string{"LDAP_GROUP_SCHEMA_ID", "STORAGE_LDAP_GROUP_SCHEMA_ID"},
Destination: &cfg.Reva.LDAP.GroupSchema.GID, Destination: &cfg.Reva.LDAP.GroupSchema.ID,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUP_SCHEMA_MAIL"}, EnvVars: []string{"LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING", "STORAGE_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING"},
Destination: &cfg.Reva.LDAP.GroupSchema.IDIsOctetString,
},
{
EnvVars: []string{"LDAP_GROUP_SCHEMA_MAIL", "STORAGE_LDAP_GROUP_SCHEMA_MAIL"},
Destination: &cfg.Reva.LDAP.GroupSchema.Mail, Destination: &cfg.Reva.LDAP.GroupSchema.Mail,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME"}, EnvVars: []string{"LDAP_GROUP_SCHEMA_DISPLAYNAME", "STORAGE_LDAP_GROUP_SCHEMA_DISPLAYNAME"},
Destination: &cfg.Reva.LDAP.GroupSchema.DisplayName, Destination: &cfg.Reva.LDAP.GroupSchema.DisplayName,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUP_SCHEMA_CN"}, EnvVars: []string{"LDAP_GROUP_SCHEMA_GROUPNAME", "STORAGE_LDAP_GROUP_SCHEMA_GROUPNAME"},
Destination: &cfg.Reva.LDAP.GroupSchema.CN, Destination: &cfg.Reva.LDAP.GroupSchema.Groupname,
}, },
{ {
EnvVars: []string{"STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER"}, EnvVars: []string{"LDAP_GROUP_SCHEMA_MEMBER", "STORAGE_LDAP_GROUP_SCHEMA_MEMBER"},
Destination: &cfg.Reva.LDAP.GroupSchema.Member,
},
{
EnvVars: []string{"LDAP_GROUP_SCHEMA_GID_NUMBER", "STORAGE_LDAP_GROUP_SCHEMA_GID_NUMBER"},
Destination: &cfg.Reva.LDAP.GroupSchema.GIDNumber, Destination: &cfg.Reva.LDAP.GroupSchema.GIDNumber,
}, },
+20 -21
View File
@@ -44,36 +44,35 @@ func DefaultConfig() *config.Config {
IDClaim: "preferred_username", IDClaim: "preferred_username",
}, },
LDAP: config.LDAP{ LDAP: config.LDAP{
Hostname: "localhost", URI: "ldaps://localhost:9126",
Port: 9126, CACert: path.Join(defaults.BaseDataPath(), "ldap", "ldap.crt"),
CACert: path.Join(defaults.BaseDataPath(), "ldap", "ldap.crt"), Insecure: false,
Insecure: false, UserBaseDN: "dc=ocis,dc=test",
BaseDN: "dc=ocis,dc=test", GroupBaseDN: "dc=ocis,dc=test",
LoginFilter: "(&(objectclass=posixAccount)(|(cn={{login}})(mail={{login}})))", UserScope: "sub",
UserFilter: "(&(objectclass=posixAccount)(|(ownclouduuid={{.OpaqueId}})(cn={{.OpaqueId}})))", GroupScope: "sub",
UserAttributeFilter: "(&(objectclass=posixAccount)({{attr}}={{value}}))", LoginAttributes: []string{"cn", "mail"},
UserFindFilter: "(&(objectclass=posixAccount)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))", UserFilter: "",
UserGroupFilter: "(&(objectclass=posixGroup)(cn={{query}}*))", GroupFilter: "",
GroupFilter: "(&(objectclass=posixGroup)(|(ownclouduuid={{.OpaqueId}})(cn={{.OpaqueId}})))", UserObjectClass: "posixAccount",
GroupAttributeFilter: "(&(objectclass=posixGroup)({{attr}}={{value}}))", GroupObjectClass: "posixGroup",
GroupFindFilter: "(&(objectclass=posixGroup)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))", BindDN: "cn=reva,ou=sysusers,dc=ocis,dc=test",
GroupMemberFilter: "(&(objectclass=posixAccount)(ownclouduuid={{.OpaqueId}}*))", BindPassword: "reva",
BindDN: "cn=reva,ou=sysusers,dc=ocis,dc=test", IDP: defaultPublicURL,
BindPassword: "reva",
IDP: defaultPublicURL,
UserSchema: config.LDAPUserSchema{ UserSchema: config.LDAPUserSchema{
UID: "ownclouduuid", ID: "ownclouduuid",
Mail: "mail", Mail: "mail",
DisplayName: "displayname", DisplayName: "displayname",
CN: "cn", Username: "cn",
UIDNumber: "uidnumber", UIDNumber: "uidnumber",
GIDNumber: "gidnumber", GIDNumber: "gidnumber",
}, },
GroupSchema: config.LDAPGroupSchema{ GroupSchema: config.LDAPGroupSchema{
GID: "cn", ID: "cn",
Mail: "mail", Mail: "mail",
DisplayName: "cn", DisplayName: "cn",
CN: "cn", Groupname: "cn",
Member: "cn",
GIDNumber: "gidnumber", GIDNumber: "gidnumber",
}, },
}, },
@@ -350,7 +350,6 @@ Other free text and markdown formatting can be used elsewhere in the document if
- [webUITags/createTags.feature:79](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUITags/createTags.feature#L79) - [webUITags/createTags.feature:79](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUITags/createTags.feature#L79)
### [When a user shares folder to a group, the sharer is shown as group in group member's sharing-sidebar](https://github.com/owncloud/web/issues/5216) ### [When a user shares folder to a group, the sharer is shown as group in group member's sharing-sidebar](https://github.com/owncloud/web/issues/5216)
- [webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature:41](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature#L41)
- [webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature:42](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature#L42) - [webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature:42](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalGroupsEdgeCases/shareWithGroupsEdgeCases.feature#L42)
### [impossible to navigate into a folder in the trashbin](https://github.com/owncloud/web/issues/1725) ### [impossible to navigate into a folder in the trashbin](https://github.com/owncloud/web/issues/1725)