OVERVIEW
We currently support three OAuth Providers, GitLab, Google, and Office365. After researching our implementation and OpenId Connect, Mattermost already supports most of OpenId Connect. Review the background reading in order to understand OpenId Connect and its relationship to OAuth. As well as the login flow for OAuth.
...
Support OpenId Connect standard for Authentication
Support Discovery Document
Support retrieving user fields currently supported in OAuth2 implementations
Either from IdToken or additional userinfo_endpoint call
Email, First Name, Last Name, Username (from Email), Nickname, AuthData
Ensure OpenId Connect works with existing OAuth providers. (Office365, Google, GitLab)
Migrate Existing OAuth2.0 providers to OpenId Connect
SCOPE
In:
OpenId Connect Authentication Provider
System Console Setup for OpenId Connect Provider
Support of OpenId Connect in Mobile/Desktop/WebApp
Out:
Google Support on Mobile
Multiple Provider Support
Plugin Interactivity
BACKGROUND READING
Document on Google’s OpenId Connect / OAuth2 implementation and the differences between them.
https://developers.google.com/identity/protocols/oauth2/openid-connect
https://openid.net/connect/
OpenId Connect Specification
TERMINOLOGY
OpenID Provider - OAuth 2.0 Authorization Server that is capable of Authenticating the End-User and providing Claims to a Relying Party about the Authentication event and the End-User.
IdToken - [JWT] that contains Claims about the Authentication event. It MAY contain other Claims.
...
At a high-level, the OpenId provider will work in the same manner as the current OAuth2 implementation. Most
Although most of the code required for performing the OAuth authorization already exists. However, it will need to be refactored in order to be used by the OpenId Connect provider. For instance, GetAuthorizationCode() retrieves the Endpoint information from the config file. The OpenId Connect provider will retrieve that information from the Discovery Document.
The steps are provided below with where that code exists for the existing OAuth implementation.
...
Mattermost sends a request to the OpenID Provider (OP). [AuthorizationEndpoint]
When creating the call to the authorization endpoint, a token gets created and stored, this allows Mattermost to verify it was the provider calling back. [GetAuthorizationCode][app/oauth.go]The OP authenticates the End-User and obtains authorization.
The user is presented with a login form from the OP, then an authorization for the requested scopes.The OP responds with a Token.
Mattermost validates the token, by retrieving it from the database and comparing Token information.(AuthorizeOAuthUser)[app/oauth.go]Mattermost send a request to the OpenId Provider. [TokenEndpoint]
Mattermost exchanges secret for AccessToken/ID Token (AuthorizeOAuthUser)[app/oauth.go]The OP responds with an ID Token and usually an Access Token.
The ID Token gets verified and decoded. [New functionality]
Some providers pass all the user info in the Id Token (Google, Exchange), therefore the login process could end here. Others [GitLab] do not return user information in the Id Token and require an additional call. [New Functionality]Mattermost requests with the Access Token to the UserInfo Endpoint.
Similar to existing call to UserApiEndpoint (AuthorizeOAuthUser)[app/oauth.go]The UserInfo Endpoint returns Claims about the End-User.
Convert Claims to model.User [New]
Similar to OAuth Providers [userFromGoogleUser]
...
Discovery Document
The OpenID Connect protocol requires the use of multiple endpoints for authenticating users, and for requesting resources including tokens, user information, and public keys.
...
model.User Property | GoogleUser | IdToken(google) | userInfo (google) | IdToken (github) | userInfo (github) | userInfo (Office365) |
---|---|---|---|---|---|---|
Username | From Email | from Email | from email | from email | from email | |
FirstName | GivenName | given_name | given_name | name split space | name split space | |
LastName | FamilyName | family_name | family_name | name - split space | name split space | |
Nickname | Nicknames[0] | nickname | nickname(?) | nickname | nickname | |
AuthData | sub | sub | sub | sub | sub | |
AuthService | "iss":"https://accounts.google.com" | "iss":"https://gitlab.com" | ||||
picture (url) locale iat (time issued) | profile picture iat | profile picture iat | profile picture iat |
Licensing
The OpenId Connect provider is planned as a E20 feature. The feature should be protected by license checks.
Permissions
There should not be any permission changes
...
There is the potential of adding two additional api commands for handling OpenId Connect.
Code Block |
---|
w.MainRouter.Handle("/openid/{service:[A-Za-z0-9]+}/complete", w.ApiHandler(completeOAuth)).Methods("GET") w.MainRouter.Handle("/openid/{service:[A-Za-z0-9]+}/login", w.ApiHandler(loginWithOAuth)).Methods("GET") w.MainRouter.Handle("/openid/{service:[A-Za-z0-9]+}/mobile_login", w.ApiHandler(mobileLoginWithOAuth)).Methods("GET") w.MainRouter.Handle("/openid/{service:[A-Za-z0-9]+}/signup", w.ApiHandler(signupWithOAuth)).Methods("GET") |
Ideally, OpenId could be handled as an additional service and with the existing code. However, that will depend on whether multiple providers are allowed. And how easily the code can be refactored to accommodate both.
CLI
No CLI changes required
...
Account Settings
Restrict user from setting
Username
Email
Similar to other OAuth providers
Logging In
WebApp -
login_controller.jsx
Add OpenIdConnect section
Is user restricted to OpenId Connect or OAuth?
Currently OAuth limited to one being turned on at a time.
I don’t think it is a technical limitation.
Mobile
loginOptions.js
Add OpenIdConnect Option
Google OAuth not supported on mobile,
Need to understand why
Will this affect OpenIdConnect?
Update to login flow
Mobile Migration -
w/ old server
New OpenId won’t be available as server won’t support.
Existing OAuth Connections will continue to work as is.
w/ new server
New OpenId will be available if configured and enabled on the server.
Existing OAuth Connections will continue to work as is.
Same endpoints, change is on server side.
Old app w/ new server
New OpenId will not be available
If that is users login method, they would not be able to login.
Existing OAuth Connections will continue to work as is.
Migration
Once an OAuth System has been migrated to OIDC, we need to understand the impact on existing users. Users will remain logged in as long as their session is valid. Once their session expires, the users will go through the new login process. They will be asked to login in their provider (or not, if already logged into their provider). Whether or not the users are asked to reauthorize usage depends on each Provider.
Each of these was tested as follows -
Remove Authorized Application from Provider
Login using current OAuth Settings
Change Configuration to use OpenId Connect for same provider, same application
Login using OpenId Connect Scopes [OpenId, Email, Profile]
Google already uses OpenId Connect as the login mechanism for OAuth. The user does not have to authorize any additional access.
GitLab
GitLab controls the user’s allowed scopes in the GitLab Application. The admin will need to add or verify users have access to [email profile openid] scopes in the Mattermost application on GitLab. Once that is done when the user logs in, the user will be asked to authorize access to the new scopes.
Office365
Office’s User.Read permission allow MM to “Read your profile”. That single permission is enough to allow the profile, email, openid scopes to operate successfully. If the application is deleted and recreated the “View your basic profile” and “View your email address” permissions request access.
Performance
The retrieval of the Discovery Document should only happen once and then be cached.
...
No immediate impact on plugins. However, we need to explore the use of the IdToken to be used between plugins and the server for authentication. Need to understand the plugin use cases better.
However, I do not understand how plugins use OAuth. Currently, they authenticate separately, I believe. But in the future, we want to look at using the IdToken between the server and plugins. There is a way for applications to use incremental authorization to request additional permissions. However, that is beyond the scope of this document.
...
CREDITS
Thanks to