User management issues when using multirealm authentication provider
Created by: safar
This is a follow up on issue #5464 and problems discovered after update to 6.2.
Environment description
I have setup GitLab 6.2 with omniauth-shibboleth authentication provider. It currently operates inside a federation consisting of 230 different Identity Providers.
The problem I have discovered is caused by the fact that username must be unique per authentication provider, which in my case is shibboleth. Technically speaking provider is shibboleth, but in most cases shibboleth is used in federated SSO (Single sign-on) communities so it consists of many different identity providers. Shibboleth is just a "proxy" between them. This multi-realm nature of federated SSO communities causes the problem.
User IDs in our federation are created by this simple rule: first letter of the name + [email protected]
, i.e. [email protected]
Scenario
Let's take this scenario as an example:
Realm: | realm1.tld | realm2.tld | realm3.tld |
---|---|---|---|
SSO Uid | [email protected] | [email protected] | [email protected] |
[email protected] | [email protected] | [email protected] | |
Generated GitLab username | john.doe | john.doe | foo.bar |
Provider | shibboleth | shibboleth | shibboleth |
John Doe can be the same person, but also it can be two different persons with the same first and last name the behaviour will be the same.
- When John Doe from realm1 logs into GitLab, it creates username john.doe by parsing first part of his email address.
- When John Doe from realm2 now tries to log into GitLab it will get error 422 and production log will have an entry like this:
ActiveRecord::RecordInvalid (Validation failed: Username has already been taken, Username already exist):
- When Foo Bar logs in it will be successfully created since his email is unique and username still doesn't exist for provider shibboleth.
validates :name, presence: true
validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }
validates :bio, length: { within: 0..255 }
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
validates :username, presence: true, uniqueness: true,
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
def username
email.match(/^[^@]*/)[0]
end
Proposed solution
Instead of parsing email to get username when using oauth providers, username should be equal to extern uid. This solution requires change in username validator since only letters, digits & '_' '-' '.' are allowed. In case of John Doe from realm1 log in, his username should equal [email protected]. That way when another user from realm2 with the same name logs in it won't have a problem since its user name will be [email protected] and will still be unique.
Or maybe it can even be an SHA hash of extern uid so username validator doesn't have to be changed.
Just a thought but is username even necessary for users authenticated by oauth providers?