Open butonic opened 4 years ago
Feedback from reviews:
@michaelstingl
A problem I ran into, which requires additional design.
We need to deal out unique uidnumbers but the graph api has no property for them. So I currently, cannot, without bendingf the rules use the graph api as the backend for glauth.
We are using glauth as an ldap server to provide posixaccounts to eos. a posixaccount
MUST have the cn
, uid
, uidNumber
, gidNumber
, and homeDirectory
attributes.
Furthermore, if we are effectively provisioning the accounts, we may need to use a specific uid range to prevent collisions with existing users in other ldap domains. See Red Hat Enterprise Linux > 6 > Identity Management Guide > 9.9. Managing Unique UID and GID Number Assignments for some background. Also we should skip some uidNumbers when looking at UID, GID, SID and RID ... who are you. which deals with mixing ids from ldap and windows. It seems to be recommended to start over 65535 to prevent collisions with local uids.
In the OS the uidNumber
becomes the numeric uid
, uid
(userid) becomes the username
or login id and cn
is the common name or display name.
The questions are:
There are two scenarios where we need an ldap server:
We could request an ldap server or credentials with write permissions for these scenarios if the guest provisioning algorithm from owncloud should be used. If another process for guest accounts exists we can assume the uidnumber to be conflict free, the storage can bo configured to use the existing ldap server.
But what if uidnumbers collide in case of a merger?
The other option is to always manage accounts ourself, which is what we do with the accounts service and provide an ldap interface for the customer so he can use it to integrate the storage and firewall.
But can and do we want to implement a scalable ldap server?
Putting users into the filesystem to let eg eos georeplicate the users for the storage makes sense.
if we use acis-accounts as the source of truth, the merge problem remains the same. We could apply same uidnumber range strategy as in Red Hat Enterprise Linux > 6 > Identity Management Guide > 9.9. Managing Unique UID and GID Number Assignments
ocis-accounts only exists to generate a uuid for users. we look up the sub@iss in the accounts service and generate a uuid if necessary.
technically, this can be replaced with a lookup of the user in an ldap server by email or username, whatever claim is sent by the oidc provider. might be a userPrincipalName or a guid. MS has the same problem for their Azure AD / graph: https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-design-concepts
The sourceAnchor
is used to link existing objects in Azure AD with objects on-premises. IT is also called immutableId
and the two names are used interchangeable. It used to default to the objectGUID
, but it can change, which is why it now defaults to ms-DS-ConsistencyGuid
. ms-DS-ConsistencyGuid
defaults to the objectGUID
, but it can also take non GUID values aka as byte arrads for legacy compatability.
Which brings us back to the mapping sub@iss to a stable attribute problem.
We need a stable attribute for federated sharing. The id must never change, but it must be mergeable / conflict free when merging two ocis instances. The only type of id that allows that are UUIDs.
Note that this kind of uniqueness is also needed for groups. But there are occasions where millions of groups are in place. And during a migration they might have to be merged. Which leads to the problem of replacing uids and gids in shares and permissions.
This is similar to cross storage moves. The storage id will change ... which will change the fileid. For ocis we plan to drop support for cross storage move and make it a copy and delete operation to notify the user that shares to that file will be removed until we implement a history of old file ids. When the storage providers cooperate we can redirect to the new target and the requesting client can update his reference.
Maybe we can implment something that can deal with changing uids and gids using a history. ms already has a sid history in ad.
currently
other approach:
changes to the uidnumber and gidnumber must be dealt with by the directory admin. should ocis support changing usernames (chmod) and acls (getfacl -R ...
& setfacl --restore=...
maybe?)?
The sub@iss won't change unless the idp product changes. oidc knows nothing about groups so we need to talk to an ldap anyway. but ldap has no persistent dentifiers unless we add our own. we could add a schema and copy the current uuid (objectguid or entryuuid or whatever) into that custom attribute. which might still collide when we have to merge two ldap directories.
If we store the sub@iss in cs3 grants we need a way to update them when the sub@iss changes due to a change of the idp product. Or we need to be able to rebuild the shares in the share manager from the storage.
For groups it will be even harder to maintain a uuid ...
we either need an ldap attribute with a uuid value we can use, or we need write access to the ldap server so we can generate the uuid on the fly.
we can define a schema for that attribute.
https://ldapwiki.com/wiki/Best%20Practices%20For%20Unique%20Identifiers
another thing we need for sharing is a way to map the claims in the idtoken / from the userinfo endpoint to an account. when sharing files with others the account might not have been provisioned yet. if we can only share with existing accounts we also need a way to map an email to that account.
to share with other users the email allows starting an oidc discovery to find the issuer for the user. the webfinger protocol allows looking up users: https://openid.net/specs/openid-connect-discovery-1_0.html#AcctURISyntax or https://openid.net/specs/openid-connect-discovery-1_0.html#EmailSyntax
another interesting link: fastfed spec https://openid.net/specs/fastfed-core-1_0-02.html#ScimSchemaGrammar very recent: https://bitbucket.org/openid/fastfed/src/master/
In the end switching the idp is the same as migrating a user.
The first user story is changing the idp due to a merger, or because an external user becomes an internal user or vice versa. In those cases the sub@iss combo will change. But we need a stable identifier for federated shares. ocis-accounts will generate and store the accounts, which consist of the uuid and a set of identities. An identity consists of an issuer, an issuer assigned id and a type. similar to the ms graph objectIdentity
resource. This allows adding multiple identities to an account.
With a generated uuid we can identify the users. Instead of generating the id ourself we should use the scim_id
or scim_externalid
claim if it is present in the oidc id token claims. That spec is still a draft, but scim and oidc are also tied together in the recent OIDC FastFed draft:https://openid.net/specs/fastfed-scim-1_0-02.html
To persist shares as acls we need the current username under which the user is known in the os. For unix this can be done by configuring pamto use ldap to resolve accounts. We could use other modules like pam_mysql or even implement new ones, but the fact that we a numeric uid and a username pair does not change. It is however optional because it is only necessary when trying to persist shares as acls to the filesystem.
When using a fuse overlay the owner user uuid and group uuid could be stored as extended attributes. shares can use an acl like syntax but with the uuid and store that in a dedicated file, because extended attributes are limited in space.
I already mentioned group uuids. Which AFAICT is only needed for federated group shares ...
hm stumbled over https://systemd.io/USER_RECORD/ again.
The oidc claims have a preferred username. we could check if a user with the name exists. either by checking /home/<username>.homedir/.identity
or a different path, eg /var/lib/ocis/<username>.homedir/.identity
.
that would be lookup by username.
We could cache the identities in glauth to enable searching other properties using ldap. then searching for recipients would have to use ldap to find accounts. or do an oidc discovery by email.
a homed
backend for glauth. well ... homed is hardcoded to /home
... but we could at least use the USER_RECORD json format ...
glauth with write support and homed backend as a minimal persistence layer for accounts
-> ocis uses ocis-glauth to persist accounts using LDAP
-> uuids are generated by accounts service and stored in glauth using LDAP
-> posixaccount.numericUid
(for os integration) is generated by accounts service and stored in glauth using LDAP
-> guests are provisioned by ocis on the fly as users using LDAP
-> same as no LDAP integration -> add LDAP schema for our uuid or configure a suited attribute
-> ocis cannot manage accounts
-> uuid must be provided by LDAP (with schema)
-> posixaccount.numericuid
must be provided by LDAP
-> guests must be provisioned by external process
We always need to look up users using username, email or our LDAP uuid that is sent by the IdP as an additional claim. sub
claim is useless to us because we cannot look up users with it. One exception: no ldap integration, means we manage all the accounts and could use sub as the uuid ... but then we leak the sub, which might be considered ok if it is a Pairwise Pseudonymous Identifier (PPID)
systemd-homed seems to evolve in the direction we need: https://github.com/systemd/systemd/blob/a9ab5cdb505d7d368c44fc02cc0183e75db1f657/docs/USERDB_AND_DESKTOPS.md#future-additions
Where are we? Starting with protocol changes in ocis-accounts:
we have a new (minimal) protobuf for the accounts service. The accounts limit themselves to
message Account {
// the non reassignable and stable account_id of an account
string account_id = 1;
// The identities that are mapped to this account
repeated Identities identities = 2; // keep track of every identity of a given user
string username = 3;
string display_name = 4;
string mail = 5;
// TODO avatar needed? because the standard claims contain it or our own avatar service will use the accountid or email to look up the avatar
repeated Group groups = 6;
}
The rpcs now follow the API recommendations from Google on
The PR for this is https://github.com/owncloud/ocis-accounts/pull/30
Some services need to be updated
glauth PR for homed implementation in https://github.com/glauth/glauth/pull/139
ocis-glauth needs https://github.com/owncloud/ocis-glauth/pull/16
./users/reva.homedir/.identity
file with this content:
{
"userName":"reva",
"uid":10001,
"gid":15000,
"emailAddress":"storage@example.org",
"realName":"Reva Inter Operability Platform",
"OwnCloudUUID":"9b02e06a-4ad0-43bd-afe9-2e4fccdc2a0a",
"privileged": {
"hashedPassword": ["$6$kvkJWETzJsEYgVM8$Mo4Pcei7K/oPvIMqVpcWuMYoItfaSrAklriG/RO4ARhI52.LCu8hFIKU1E4j1DDW5H8LRxH0DYT31L36qB3au1"]
}
}
json data is currently not signed
the hashed password is created using bcrypt. I just created a user locally, set his password and copied the string from /etc/shadow
. glauth uses https://github.com/tredoe/osutil/user/crypt to parse more hashes than provided by the stdlib.
all users are indexed using bleve (it will create a homed.bleve
directory, use the bleve cli to examine the index)
ownclouduuid
attributeAfter adding all the changed repos to your ocis go.mod
replace github.com/owncloud/ocis-accounts => ../ocis-accounts
replace github.com/owncloud/ocis-proxy => ../ocis-proxy
replace github.com/owncloud/ocis-migration => ../ocis-migration
replace github.com/owncloud/ocis-glauth => ../ocis-glauth
replace github.com/glauth/glauth => ../glauth
the only thing that currently works is listing users using the api gateway:
$ curl 'http://localhost:8082/rpc' \
-H 'Content-type: application/json' \
-H 'Accept: */*' \
-H 'Origin: http://localhost:8082' \
-d '{"service":"com.owncloud.api.accounts","endpoint":"AccountsService.ListAccounts","request":{}}'
{"accounts":[{"accountId":"9b02e06a-4ad0-43bd-afe9-2e4fccdc2a0a","username":"reva","mail":"storage@example.org"},{"accountId":"e0b79cfd-fa8c-436b-aca5-0a45fbd9e38c","username":"einstein","mail":"einstein@example.org"}]}
eq
, and
, or
, and not
Remote key is https://jira.owncloud.com/browse/OC-1972
next steps
We need to use the ocis-accounts service as the user backend. It contains normal users and guest accounts that we want to make accessible using LDAP so that kopano can access them.
Tasks
ocis-glauth tasks @butonic
displayName
(currently surname)ocis-accounts Tasks
ocis-proxy steps (order is important) @refs @IljaN
ocis-pkg
x-access-token
ocis-settings Tasks @kulmann
x-access-token
header using shared secret, see code reference, see issueme
in URLs as placeholder for logged in uuidOther
Estimation