feat: add azure provider templates (#5441)

Adds possibility to manage and use Microsoft Azure template based providers
This commit is contained in:
Livio Spring
2023-03-15 07:48:37 +01:00
committed by GitHub
parent 93e1fe0056
commit 5a307afe62
30 changed files with 2843 additions and 60 deletions

View File

@@ -15,7 +15,7 @@ import (
const (
authURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/authorize"
tokenURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/token"
userinfoURL string = "https://graph.microsoft.com/oidc/userinfo"
userinfoURL string = "https://graph.microsoft.com/v1.0/me"
)
// TenantType are the well known tenant types to scope the users that can authenticate. TenantType is not an
@@ -73,7 +73,7 @@ func WithOAuthOptions(opts ...oauth.ProviderOpts) ProviderOptions {
// New creates an AzureAD provider using the [oauth.Provider] (OAuth 2.0 generic provider).
// By default, it uses the [CommonTenant] and unverified emails.
func New(name, clientID, clientSecret, redirectURI string, opts ...ProviderOptions) (*Provider, error) {
func New(name, clientID, clientSecret, redirectURI string, scopes []string, opts ...ProviderOptions) (*Provider, error) {
provider := &Provider{
tenant: CommonTenant,
options: make([]oauth.ProviderOpts, 0),
@@ -81,7 +81,7 @@ func New(name, clientID, clientSecret, redirectURI string, opts ...ProviderOptio
for _, opt := range opts {
opt(provider)
}
config := newConfig(provider.tenant, clientID, clientSecret, redirectURI, []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail})
config := newConfig(provider.tenant, clientID, clientSecret, redirectURI, scopes)
rp, err := oauth.New(
config,
name,
@@ -121,34 +121,38 @@ func newConfig(tenant TenantType, clientID, secret, callbackURL string, scopes [
// AzureAD does not return an `email_verified` claim.
// The verification can be automatically activated on the provider ([WithEmailVerified])
type User struct {
Sub string `json:"sub"`
FamilyName string `json:"family_name"`
GivenName string `json:"given_name"`
Name string `json:"name"`
PreferredUsername string `json:"preferred_username"`
Email domain.EmailAddress `json:"email"`
Picture string `json:"picture"`
ID string `json:"id"`
BusinessPhones []domain.PhoneNumber `json:"businessPhones"`
DisplayName string `json:"displayName"`
FirstName string `json:"givenName"`
JobTitle string `json:"jobTitle"`
Email domain.EmailAddress `json:"mail"`
MobilePhone domain.PhoneNumber `json:"mobilePhone"`
OfficeLocation string `json:"officeLocation"`
PreferredLanguage string `json:"preferredLanguage"`
LastName string `json:"surname"`
UserPrincipalName string `json:"userPrincipalName"`
isEmailVerified bool
}
// GetID is an implementation of the [idp.User] interface.
func (u *User) GetID() string {
return u.Sub
return u.ID
}
// GetFirstName is an implementation of the [idp.User] interface.
func (u *User) GetFirstName() string {
return u.GivenName
return u.FirstName
}
// GetLastName is an implementation of the [idp.User] interface.
func (u *User) GetLastName() string {
return u.FamilyName
return u.LastName
}
// GetDisplayName is an implementation of the [idp.User] interface.
func (u *User) GetDisplayName() string {
return u.Name
return u.DisplayName
}
// GetNickname is an implementation of the [idp.User] interface.
@@ -159,11 +163,16 @@ func (u *User) GetNickname() string {
// GetPreferredUsername is an implementation of the [idp.User] interface.
func (u *User) GetPreferredUsername() string {
return u.PreferredUsername
return u.UserPrincipalName
}
// GetEmail is an implementation of the [idp.User] interface.
func (u *User) GetEmail() domain.EmailAddress {
if u.Email == "" {
// if the user used a social login on Azure as well, the email will be empty
// but is used as username
return domain.EmailAddress(u.UserPrincipalName)
}
return u.Email
}
@@ -188,10 +197,8 @@ func (u *User) IsPhoneVerified() bool {
}
// GetPreferredLanguage is an implementation of the [idp.User] interface.
// It returns [language.Und] because AzureAD does not provide the user's language
func (u *User) GetPreferredLanguage() language.Tag {
// AzureAD does not provide the user's language
return language.Und
return language.Make(u.PreferredLanguage)
}
// GetProfile is an implementation of the [idp.User] interface.
@@ -202,5 +209,5 @@ func (u *User) GetProfile() string {
// GetAvatarURL is an implementation of the [idp.User] interface.
func (u *User) GetAvatarURL() string {
return u.Picture
return ""
}