mirror of https://github.com/go-gitea/gitea
Add microsoft oauth2 providers (#16544)
* Clean up oauth2 providers Signed-off-by: Andrew Thornton <art27@cantab.net> * Add AzureAD, AzureADv2, MicrosoftOnline OAuth2 providers Signed-off-by: Andrew Thornton <art27@cantab.net> * Apply suggestions from code review * remove unused Scopes Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>pull/16634/head^2
parent
7e7006e00d
commit
ab9bb54144
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 792 B |
@ -0,0 +1,33 @@ |
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2 |
||||
|
||||
// BaseProvider represents a common base for Provider
|
||||
type BaseProvider struct { |
||||
name string |
||||
displayName string |
||||
} |
||||
|
||||
// Name provides the technical name for this provider
|
||||
func (b *BaseProvider) Name() string { |
||||
return b.name |
||||
} |
||||
|
||||
// DisplayName returns the friendly name for this provider
|
||||
func (b *BaseProvider) DisplayName() string { |
||||
return b.displayName |
||||
} |
||||
|
||||
// Image returns an image path for this provider
|
||||
func (b *BaseProvider) Image() string { |
||||
return "/assets/img/auth/" + b.name + ".png" |
||||
} |
||||
|
||||
// CustomURLSettings returns the custom url settings for this provider
|
||||
func (b *BaseProvider) CustomURLSettings() *CustomURLSettings { |
||||
return nil |
||||
} |
||||
|
||||
var _ (Provider) = &BaseProvider{} |
@ -0,0 +1,118 @@ |
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2 |
||||
|
||||
import ( |
||||
"code.gitea.io/gitea/modules/setting" |
||||
|
||||
"github.com/markbates/goth" |
||||
"github.com/markbates/goth/providers/azureadv2" |
||||
"github.com/markbates/goth/providers/gitea" |
||||
"github.com/markbates/goth/providers/github" |
||||
"github.com/markbates/goth/providers/gitlab" |
||||
"github.com/markbates/goth/providers/mastodon" |
||||
"github.com/markbates/goth/providers/nextcloud" |
||||
) |
||||
|
||||
// CustomProviderNewFn creates a goth.Provider using a custom url mapping
|
||||
type CustomProviderNewFn func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) |
||||
|
||||
// CustomProvider is a GothProvider that has CustomURL features
|
||||
type CustomProvider struct { |
||||
BaseProvider |
||||
customURLSettings *CustomURLSettings |
||||
newFn CustomProviderNewFn |
||||
} |
||||
|
||||
// CustomURLSettings returns the CustomURLSettings for this provider
|
||||
func (c *CustomProvider) CustomURLSettings() *CustomURLSettings { |
||||
return c.customURLSettings |
||||
} |
||||
|
||||
// CreateGothProvider creates a GothProvider from this Provider
|
||||
func (c *CustomProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) { |
||||
custom := c.customURLSettings.OverrideWith(source.CustomURLMapping) |
||||
|
||||
return c.newFn(source.ClientID, source.ClientSecret, callbackURL, custom) |
||||
} |
||||
|
||||
// NewCustomProvider is a constructor function for custom providers
|
||||
func NewCustomProvider(name, displayName string, customURLSetting *CustomURLSettings, newFn CustomProviderNewFn) *CustomProvider { |
||||
return &CustomProvider{ |
||||
BaseProvider: BaseProvider{ |
||||
name: name, |
||||
displayName: displayName, |
||||
}, |
||||
customURLSettings: customURLSetting, |
||||
newFn: newFn, |
||||
} |
||||
} |
||||
|
||||
var _ (GothProvider) = &CustomProvider{} |
||||
|
||||
func init() { |
||||
RegisterGothProvider(NewCustomProvider( |
||||
"github", "GitHub", &CustomURLSettings{ |
||||
TokenURL: availableAttribute(gitea.TokenURL), |
||||
AuthURL: availableAttribute(github.AuthURL), |
||||
ProfileURL: availableAttribute(github.ProfileURL), |
||||
EmailURL: availableAttribute(github.EmailURL), |
||||
}, |
||||
func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
scopes := []string{} |
||||
if setting.OAuth2Client.EnableAutoRegistration { |
||||
scopes = append(scopes, "user:email") |
||||
} |
||||
return github.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, custom.EmailURL, scopes...), nil |
||||
})) |
||||
|
||||
RegisterGothProvider(NewCustomProvider( |
||||
"gitlab", "GitLab", &CustomURLSettings{ |
||||
AuthURL: availableAttribute(gitlab.AuthURL), |
||||
TokenURL: availableAttribute(gitlab.TokenURL), |
||||
ProfileURL: availableAttribute(gitlab.ProfileURL), |
||||
}, func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
return gitlab.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL, "read_user"), nil |
||||
})) |
||||
|
||||
RegisterGothProvider(NewCustomProvider( |
||||
"gitea", "Gitea", &CustomURLSettings{ |
||||
TokenURL: requiredAttribute(gitea.TokenURL), |
||||
AuthURL: requiredAttribute(gitea.AuthURL), |
||||
ProfileURL: requiredAttribute(gitea.ProfileURL), |
||||
}, |
||||
func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
return gitea.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL), nil |
||||
})) |
||||
|
||||
RegisterGothProvider(NewCustomProvider( |
||||
"nextcloud", "Nextcloud", &CustomURLSettings{ |
||||
TokenURL: requiredAttribute(nextcloud.TokenURL), |
||||
AuthURL: requiredAttribute(nextcloud.AuthURL), |
||||
ProfileURL: requiredAttribute(nextcloud.ProfileURL), |
||||
}, |
||||
func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
return nextcloud.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL, custom.TokenURL, custom.ProfileURL), nil |
||||
})) |
||||
|
||||
RegisterGothProvider(NewCustomProvider( |
||||
"mastodon", "Mastodon", &CustomURLSettings{ |
||||
AuthURL: requiredAttribute(mastodon.InstanceURL), |
||||
}, |
||||
func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
return mastodon.NewCustomisedURL(clientID, secret, callbackURL, custom.AuthURL), nil |
||||
})) |
||||
|
||||
RegisterGothProvider(NewCustomProvider( |
||||
"azureadv2", "Azure AD v2", &CustomURLSettings{ |
||||
Tenant: requiredAttribute("organizations"), |
||||
}, |
||||
func(clientID, secret, callbackURL string, custom *CustomURLMapping) (goth.Provider, error) { |
||||
return azureadv2.New(clientID, secret, callbackURL, azureadv2.ProviderOptions{ |
||||
Tenant: azureadv2.TenantType(custom.Tenant), |
||||
}), nil |
||||
}, |
||||
)) |
||||
} |
@ -0,0 +1,52 @@ |
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2 |
||||
|
||||
import ( |
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/setting" |
||||
|
||||
"github.com/markbates/goth" |
||||
"github.com/markbates/goth/providers/openidConnect" |
||||
) |
||||
|
||||
// OpenIDProvider is a GothProvider for OpenID
|
||||
type OpenIDProvider struct { |
||||
} |
||||
|
||||
// Name provides the technical name for this provider
|
||||
func (o *OpenIDProvider) Name() string { |
||||
return "openidconnect" |
||||
} |
||||
|
||||
// DisplayName returns the friendly name for this provider
|
||||
func (o *OpenIDProvider) DisplayName() string { |
||||
return "OpenID Connect" |
||||
} |
||||
|
||||
// Image returns an image path for this provider
|
||||
func (o *OpenIDProvider) Image() string { |
||||
return "/assets/img/auth/openid_connect.svg" |
||||
} |
||||
|
||||
// CreateGothProvider creates a GothProvider from this Provider
|
||||
func (o *OpenIDProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) { |
||||
provider, err := openidConnect.New(source.ClientID, source.ClientSecret, callbackURL, source.OpenIDConnectAutoDiscoveryURL, setting.OAuth2Client.OpenIDConnectScopes...) |
||||
if err != nil { |
||||
log.Warn("Failed to create OpenID Connect Provider with name '%s' with url '%s': %v", providerName, source.OpenIDConnectAutoDiscoveryURL, err) |
||||
} |
||||
return provider, err |
||||
} |
||||
|
||||
// CustomURLSettings returns the custom url settings for this provider
|
||||
func (o *OpenIDProvider) CustomURLSettings() *CustomURLSettings { |
||||
return nil |
||||
} |
||||
|
||||
var _ (GothProvider) = &OpenIDProvider{} |
||||
|
||||
func init() { |
||||
RegisterGothProvider(&OpenIDProvider{}) |
||||
} |
@ -0,0 +1,108 @@ |
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2 |
||||
|
||||
import ( |
||||
"code.gitea.io/gitea/modules/setting" |
||||
|
||||
"github.com/markbates/goth" |
||||
"github.com/markbates/goth/providers/azuread" |
||||
"github.com/markbates/goth/providers/bitbucket" |
||||
"github.com/markbates/goth/providers/discord" |
||||
"github.com/markbates/goth/providers/dropbox" |
||||
"github.com/markbates/goth/providers/facebook" |
||||
"github.com/markbates/goth/providers/google" |
||||
"github.com/markbates/goth/providers/microsoftonline" |
||||
"github.com/markbates/goth/providers/twitter" |
||||
"github.com/markbates/goth/providers/yandex" |
||||
) |
||||
|
||||
// SimpleProviderNewFn create goth.Providers without custom url features
|
||||
type SimpleProviderNewFn func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider |
||||
|
||||
// SimpleProvider is a GothProvider which does not have custom url features
|
||||
type SimpleProvider struct { |
||||
BaseProvider |
||||
scopes []string |
||||
newFn SimpleProviderNewFn |
||||
} |
||||
|
||||
// CreateGothProvider creates a GothProvider from this Provider
|
||||
func (c *SimpleProvider) CreateGothProvider(providerName, callbackURL string, source *Source) (goth.Provider, error) { |
||||
return c.newFn(source.ClientID, source.ClientSecret, callbackURL, c.scopes...), nil |
||||
} |
||||
|
||||
// NewSimpleProvider is a constructor function for simple providers
|
||||
func NewSimpleProvider(name, displayName string, scopes []string, newFn SimpleProviderNewFn) *SimpleProvider { |
||||
return &SimpleProvider{ |
||||
BaseProvider: BaseProvider{ |
||||
name: name, |
||||
displayName: displayName, |
||||
}, |
||||
scopes: scopes, |
||||
newFn: newFn, |
||||
} |
||||
} |
||||
|
||||
var _ (GothProvider) = &SimpleProvider{} |
||||
|
||||
func init() { |
||||
RegisterGothProvider( |
||||
NewSimpleProvider("bitbucket", "Bitbucket", []string{"account"}, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return bitbucket.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
RegisterGothProvider( |
||||
NewSimpleProvider("dropbox", "Dropbox", nil, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return dropbox.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
RegisterGothProvider(NewSimpleProvider("facebook", "Facebook", nil, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return facebook.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
// named gplus due to legacy gplus -> google migration (Google killed Google+). This ensures old connections still work
|
||||
RegisterGothProvider(NewSimpleProvider("gplus", "Google", []string{"email"}, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
if setting.OAuth2Client.UpdateAvatar || setting.OAuth2Client.EnableAutoRegistration { |
||||
scopes = append(scopes, "profile") |
||||
} |
||||
return google.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
RegisterGothProvider(NewSimpleProvider("twitter", "Twitter", nil, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return twitter.New(clientKey, secret, callbackURL) |
||||
})) |
||||
|
||||
RegisterGothProvider(NewSimpleProvider("discord", "Discord", []string{discord.ScopeIdentify, discord.ScopeEmail}, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return discord.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
// See https://tech.yandex.com/passport/doc/dg/reference/response-docpage/
|
||||
RegisterGothProvider(NewSimpleProvider("yandex", "Yandex", []string{"login:email", "login:info", "login:avatar"}, |
||||
func(clientKey, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return yandex.New(clientKey, secret, callbackURL, scopes...) |
||||
})) |
||||
|
||||
RegisterGothProvider(NewSimpleProvider( |
||||
"azuread", "Azure AD", nil, |
||||
func(clientID, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return azuread.New(clientID, secret, callbackURL, nil, scopes...) |
||||
}, |
||||
)) |
||||
|
||||
RegisterGothProvider(NewSimpleProvider( |
||||
"microsoftonline", "Microsoft Online", nil, |
||||
func(clientID, secret, callbackURL string, scopes ...string) goth.Provider { |
||||
return microsoftonline.New(clientID, secret, callbackURL, scopes...) |
||||
}, |
||||
)) |
||||
|
||||
} |
@ -0,0 +1,19 @@ |
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2 |
||||
|
||||
// Name returns the provider name of this source
|
||||
func (source *Source) Name() string { |
||||
return source.Provider |
||||
} |
||||
|
||||
// DisplayName returns the display name of this source
|
||||
func (source *Source) DisplayName() string { |
||||
provider, has := gothProviders[source.Provider] |
||||
if !has { |
||||
return source.Provider |
||||
} |
||||
return provider.DisplayName() |
||||
} |
@ -0,0 +1,22 @@ |
||||
Copyright (c) 2014 Mark Bates |
||||
|
||||
MIT License |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
||||
"Software"), to deal in the Software without restriction, including |
||||
without limitation the rights to use, copy, modify, merge, publish, |
||||
distribute, sublicense, and/or sell copies of the Software, and to |
||||
permit persons to whom the Software is furnished to do so, subject to |
||||
the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,36 @@ |
||||
package defaults |
||||
|
||||
func String(s1, s2 string) string { |
||||
if s1 == "" { |
||||
return s2 |
||||
} |
||||
return s1 |
||||
} |
||||
|
||||
func Int(i1, i2 int) int { |
||||
if i1 == 0 { |
||||
return i2 |
||||
} |
||||
return i1 |
||||
} |
||||
|
||||
func Int64(i1, i2 int64) int64 { |
||||
if i1 == 0 { |
||||
return i2 |
||||
} |
||||
return i1 |
||||
} |
||||
|
||||
func Float32(i1, i2 float32) float32 { |
||||
if i1 == 0.0 { |
||||
return i2 |
||||
} |
||||
return i1 |
||||
} |
||||
|
||||
func Float64(i1, i2 float64) float64 { |
||||
if i1 == 0.0 { |
||||
return i2 |
||||
} |
||||
return i1 |
||||
} |
@ -0,0 +1,187 @@ |
||||
// Package azuread implements the OAuth2 protocol for authenticating users through AzureAD.
|
||||
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
|
||||
// To use microsoft personal account use microsoftonline provider
|
||||
package azuread |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"net/http" |
||||
"net/url" |
||||
"strings" |
||||
|
||||
"github.com/markbates/goth" |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
const ( |
||||
authURL string = "https://login.microsoftonline.com/common/oauth2/authorize" |
||||
tokenURL string = "https://login.microsoftonline.com/common/oauth2/token" |
||||
endpointProfile string = "https://graph.windows.net/me?api-version=1.6" |
||||
graphAPIResource string = "https://graph.windows.net/" |
||||
) |
||||
|
||||
// New creates a new AzureAD provider, and sets up important connection details.
|
||||
// You should always call `AzureAD.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, resources []string, scopes ...string) *Provider { |
||||
p := &Provider{ |
||||
ClientKey: clientKey, |
||||
Secret: secret, |
||||
CallbackURL: callbackURL, |
||||
providerName: "azuread", |
||||
} |
||||
|
||||
p.resources = make([]string, 0, 1+len(resources)) |
||||
p.resources = append(p.resources, graphAPIResource) |
||||
p.resources = append(p.resources, resources...) |
||||
|
||||
p.config = newConfig(p, scopes) |
||||
return p |
||||
} |
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing AzureAD.
|
||||
type Provider struct { |
||||
ClientKey string |
||||
Secret string |
||||
CallbackURL string |
||||
HTTPClient *http.Client |
||||
config *oauth2.Config |
||||
providerName string |
||||
resources []string |
||||
} |
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string { |
||||
return p.providerName |
||||
} |
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) { |
||||
p.providerName = name |
||||
} |
||||
|
||||
// Client is HTTP client to be used in all fetch operations.
|
||||
func (p *Provider) Client() *http.Client { |
||||
return goth.HTTPClientWithFallBack(p.HTTPClient) |
||||
} |
||||
|
||||
// Debug is a no-op for the package.
|
||||
func (p *Provider) Debug(debug bool) {} |
||||
|
||||
// BeginAuth asks AzureAD for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) { |
||||
authURL := p.config.AuthCodeURL(state) |
||||
|
||||
// Azure ad requires at least one resource
|
||||
authURL += "&resource=" + url.QueryEscape(strings.Join(p.resources, " ")) |
||||
|
||||
return &Session{ |
||||
AuthURL: authURL, |
||||
}, nil |
||||
} |
||||
|
||||
// FetchUser will go to AzureAD and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { |
||||
msSession := session.(*Session) |
||||
user := goth.User{ |
||||
AccessToken: msSession.AccessToken, |
||||
Provider: p.Name(), |
||||
ExpiresAt: msSession.ExpiresAt, |
||||
} |
||||
|
||||
if user.AccessToken == "" { |
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) |
||||
} |
||||
|
||||
req, err := http.NewRequest("GET", endpointProfile, nil) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
|
||||
req.Header.Set(authorizationHeader(msSession)) |
||||
|
||||
response, err := p.Client().Do(req) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
defer response.Body.Close() |
||||
|
||||
if response.StatusCode != http.StatusOK { |
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode) |
||||
} |
||||
|
||||
err = userFromReader(response.Body, &user) |
||||
return user, err |
||||
} |
||||
|
||||
//RefreshTokenAvailable refresh token is provided by auth provider or not
|
||||
func (p *Provider) RefreshTokenAvailable() bool { |
||||
return true |
||||
} |
||||
|
||||
//RefreshToken get new access token based on the refresh token
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) { |
||||
token := &oauth2.Token{RefreshToken: refreshToken} |
||||
ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token) |
||||
newToken, err := ts.Token() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return newToken, err |
||||
} |
||||
|
||||
func newConfig(provider *Provider, scopes []string) *oauth2.Config { |
||||
c := &oauth2.Config{ |
||||
ClientID: provider.ClientKey, |
||||
ClientSecret: provider.Secret, |
||||
RedirectURL: provider.CallbackURL, |
||||
Endpoint: oauth2.Endpoint{ |
||||
AuthURL: authURL, |
||||
TokenURL: tokenURL, |
||||
}, |
||||
Scopes: []string{}, |
||||
} |
||||
|
||||
if len(scopes) > 0 { |
||||
for _, scope := range scopes { |
||||
c.Scopes = append(c.Scopes, scope) |
||||
} |
||||
} else { |
||||
c.Scopes = append(c.Scopes, "user_impersonation") |
||||
} |
||||
|
||||
return c |
||||
} |
||||
|
||||
func userFromReader(r io.Reader, user *goth.User) error { |
||||
u := struct { |
||||
Name string `json:"name"` |
||||
Email string `json:"mail"` |
||||
FirstName string `json:"givenName"` |
||||
LastName string `json:"surname"` |
||||
NickName string `json:"mailNickname"` |
||||
UserPrincipalName string `json:"userPrincipalName"` |
||||
Location string `json:"usageLocation"` |
||||
}{} |
||||
|
||||
err := json.NewDecoder(r).Decode(&u) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
user.Email = u.Email |
||||
user.Name = u.Name |
||||
user.FirstName = u.FirstName |
||||
user.LastName = u.LastName |
||||
user.NickName = u.Name |
||||
user.Location = u.Location |
||||
user.UserID = u.UserPrincipalName //AzureAD doesn't provide separate user_id
|
||||
|
||||
return nil |
||||
} |
||||
|
||||
func authorizationHeader(session *Session) (string, string) { |
||||
return "Authorization", fmt.Sprintf("Bearer %s", session.AccessToken) |
||||
} |
@ -0,0 +1,63 @@ |
||||
package azuread |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/markbates/goth" |
||||
) |
||||
|
||||
// Session is the implementation of `goth.Session` for accessing AzureAD.
|
||||
type Session struct { |
||||
AuthURL string |
||||
AccessToken string |
||||
RefreshToken string |
||||
ExpiresAt time.Time |
||||
} |
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Facebook provider.
|
||||
func (s Session) GetAuthURL() (string, error) { |
||||
if s.AuthURL == "" { |
||||
return "", errors.New(goth.NoAuthUrlErrorMessage) |
||||
} |
||||
|
||||
return s.AuthURL, nil |
||||
} |
||||
|
||||
// Authorize the session with AzureAD and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) { |
||||
p := provider.(*Provider) |
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code")) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !token.Valid() { |
||||
return "", errors.New("invalid token received from provider") |
||||
} |
||||
|
||||
s.AccessToken = token.AccessToken |
||||
s.RefreshToken = token.RefreshToken |
||||
s.ExpiresAt = token.Expiry |
||||
|
||||
return token.AccessToken, err |
||||
} |
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string { |
||||
b, _ := json.Marshal(s) |
||||
return string(b) |
||||
} |
||||
|
||||
func (s Session) String() string { |
||||
return s.Marshal() |
||||
} |
||||
|
||||
// UnmarshalSession wil unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { |
||||
session := &Session{} |
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(session) |
||||
return session, err |
||||
} |
@ -0,0 +1,233 @@ |
||||
package azureadv2 |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"io/ioutil" |
||||
"net/http" |
||||
|
||||
"github.com/markbates/goth" |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// also https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints
|
||||
const ( |
||||
authURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/authorize" |
||||
tokenURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/token" |
||||
graphAPIResource string = "https://graph.microsoft.com/v1.0/" |
||||
) |
||||
|
||||
type ( |
||||
// TenantType are the well known tenant types to scope the users that can authenticate. TenantType is not an
|
||||
// exclusive list of Azure Tenants which can be used. A consumer can also use their own Tenant ID to scope
|
||||
// authentication to their specific Tenant either through the Tenant ID or the friendly domain name.
|
||||
//
|
||||
// see also https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints
|
||||
TenantType string |
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing AzureAD V2.
|
||||
Provider struct { |
||||
ClientKey string |
||||
Secret string |
||||
CallbackURL string |
||||
HTTPClient *http.Client |
||||
config *oauth2.Config |
||||
providerName string |
||||
} |
||||
|
||||
// ProviderOptions are the collection of optional configuration to provide when constructing a Provider
|
||||
ProviderOptions struct { |
||||
Scopes []ScopeType |
||||
Tenant TenantType |
||||
} |
||||
) |
||||
|
||||
// These are the well known Azure AD Tenants. These are not an exclusive list of all Tenants
|
||||
//
|
||||
// See also https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints
|
||||
const ( |
||||
// CommonTenant allows users with both personal Microsoft accounts and work/school accounts from Azure Active
|
||||
// Directory to sign into the application.
|
||||
CommonTenant TenantType = "common" |
||||
|
||||
// OrganizationsTenant allows only users with work/school accounts from Azure Active Directory to sign into the application.
|
||||
OrganizationsTenant TenantType = "organizations" |
||||
|
||||
// ConsumersTenant allows only users with personal Microsoft accounts (MSA) to sign into the application.
|
||||
ConsumersTenant TenantType = "consumers" |
||||
) |
||||
|
||||
// New creates a new AzureAD provider, and sets up important connection details.
|
||||
// You should always call `AzureAD.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, opts ProviderOptions) *Provider { |
||||
p := &Provider{ |
||||
ClientKey: clientKey, |
||||
Secret: secret, |
||||
CallbackURL: callbackURL, |
||||
providerName: "azureadv2", |
||||
} |
||||
|
||||
p.config = newConfig(p, opts) |
||||
return p |
||||
} |
||||
|
||||
func newConfig(provider *Provider, opts ProviderOptions) *oauth2.Config { |
||||
tenant := opts.Tenant |
||||
if tenant == "" { |
||||
tenant = CommonTenant |
||||
} |
||||
|
||||
c := &oauth2.Config{ |
||||
ClientID: provider.ClientKey, |
||||
ClientSecret: provider.Secret, |
||||
RedirectURL: provider.CallbackURL, |
||||
Endpoint: oauth2.Endpoint{ |
||||
AuthURL: fmt.Sprintf(authURLTemplate, tenant), |
||||
TokenURL: fmt.Sprintf(tokenURLTemplate, tenant), |
||||
}, |
||||
Scopes: []string{}, |
||||
} |
||||
|
||||
if len(opts.Scopes) > 0 { |
||||
c.Scopes = append(c.Scopes, scopesToStrings(opts.Scopes...)...) |
||||
} else { |
||||
defaultScopes := scopesToStrings(OpenIDScope, ProfileScope, EmailScope, UserReadScope) |
||||
c.Scopes = append(c.Scopes, defaultScopes...) |
||||
} |
||||
|
||||
return c |
||||
} |
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string { |
||||
return p.providerName |
||||
} |
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) { |
||||
p.providerName = name |
||||
} |
||||
|
||||
// Client is HTTP client to be used in all fetch operations.
|
||||
func (p *Provider) Client() *http.Client { |
||||
return goth.HTTPClientWithFallBack(p.HTTPClient) |
||||
} |
||||
|
||||
// Debug is a no-op for the package
|
||||
func (p *Provider) Debug(debug bool) {} |
||||
|
||||
// BeginAuth asks for an authentication end-point for AzureAD.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) { |
||||
authURL := p.config.AuthCodeURL(state) |
||||
|
||||
return &Session{ |
||||
AuthURL: authURL, |
||||
}, nil |
||||
} |
||||
|
||||
// FetchUser will go to AzureAD and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { |
||||
msSession := session.(*Session) |
||||
user := goth.User{ |
||||
AccessToken: msSession.AccessToken, |
||||
Provider: p.Name(), |
||||
ExpiresAt: msSession.ExpiresAt, |
||||
} |
||||
|
||||
if user.AccessToken == "" { |
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) |
||||
} |
||||
|
||||
req, err := http.NewRequest("GET", graphAPIResource+"me", nil) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
|
||||
req.Header.Set(authorizationHeader(msSession)) |
||||
|
||||
response, err := p.Client().Do(req) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
defer response.Body.Close() |
||||
|
||||
if response.StatusCode != http.StatusOK { |
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode) |
||||
} |
||||
|
||||
err = userFromReader(response.Body, &user) |
||||
user.AccessToken = msSession.AccessToken |
||||
user.RefreshToken = msSession.RefreshToken |
||||
user.ExpiresAt = msSession.ExpiresAt |
||||
return user, err |
||||
} |
||||
|
||||
//RefreshTokenAvailable refresh token is provided by auth provider or not
|
||||
func (p *Provider) RefreshTokenAvailable() bool { |
||||
return true |
||||
} |
||||
|
||||
//RefreshToken get new access token based on the refresh token
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) { |
||||
token := &oauth2.Token{RefreshToken: refreshToken} |
||||
ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token) |
||||
newToken, err := ts.Token() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return newToken, err |
||||
} |
||||
|
||||
func authorizationHeader(session *Session) (string, string) { |
||||
return "Authorization", fmt.Sprintf("Bearer %s", session.AccessToken) |
||||
} |
||||
|
||||
func userFromReader(r io.Reader, user *goth.User) error { |
||||
u := struct { |
||||
ID string `json:"id"` // The unique identifier for the user.
|
||||
BusinessPhones []string `json:"businessPhones"` // The user's phone numbers.
|
||||
DisplayName string `json:"displayName"` // The name displayed in the address book for the user.
|
||||
FirstName string `json:"givenName"` // The first name of the user.
|
||||
JobTitle string `json:"jobTitle"` // The user's job title.
|
||||
Email string `json:"mail"` // The user's email address.
|
||||
MobilePhone string `json:"mobilePhone"` // The user's cellphone number.
|
||||
OfficeLocation string `json:"officeLocation"` // The user's physical office location.
|
||||
PreferredLanguage string `json:"preferredLanguage"` // The user's language of preference.
|
||||
LastName string `json:"surname"` // The last name of the user.
|
||||
UserPrincipalName string `json:"userPrincipalName"` // The user's principal name.
|
||||
}{} |
||||
|
||||
userBytes, err := ioutil.ReadAll(r) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := json.Unmarshal(userBytes, &u); err != nil { |
||||
return err |
||||
} |
||||
|
||||
user.Email = u.Email |
||||
user.Name = u.DisplayName |
||||
user.FirstName = u.FirstName |
||||
user.LastName = u.LastName |
||||
user.NickName = u.DisplayName |
||||
user.Location = u.OfficeLocation |
||||
user.UserID = u.ID |
||||
user.AvatarURL = graphAPIResource + fmt.Sprintf("users/%s/photo/$value", u.ID) |
||||
// Make sure all of the information returned is available via RawData
|
||||
if err := json.Unmarshal(userBytes, &user.RawData); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func scopesToStrings(scopes ...ScopeType) []string { |
||||
strs := make([]string, len(scopes)) |
||||
for i := 0; i < len(scopes); i++ { |
||||
strs[i] = string(scopes[i]) |
||||
} |
||||
return strs |
||||
} |
@ -0,0 +1,714 @@ |
||||
package azureadv2 |
||||
|
||||
type ( |
||||
// ScopeType are the well known scopes which can be requested
|
||||
ScopeType string |
||||
) |
||||
|
||||
// OpenID Permissions
|
||||
//
|
||||
// You can use these permissions to specify artifacts that you want returned in Azure AD authorization and token
|
||||
// requests. They are supported differently by the Azure AD v1.0 and v2.0 endpoints.
|
||||
//
|
||||
// With the Azure AD (v1.0) endpoint, only the openid permission is used. You specify it in the scope parameter in an
|
||||
// authorization request to return an ID token when you use the OpenID Connect protocol to sign in a user to your app.
|
||||
// For more information, see Authorize access to web applications using OpenID Connect and Azure Active Directory. To
|
||||
// successfully return an ID token, you must also make sure that the User.Read permission is configured when you
|
||||
// register your app.
|
||||
//
|
||||
// With the Azure AD v2.0 endpoint, you specify the offline_access permission in the scope parameter to explicitly
|
||||
// request a refresh token when using the OAuth 2.0 or OpenID Connect protocols. With OpenID Connect, you specify the
|
||||
// openid permission to request an ID token. You can also specify the email permission, profile permission, or both to
|
||||
// return additional claims in the ID token. You do not need to specify User.Read to return an ID token with the v2.0
|
||||
// endpoint. For more information, see OpenID Connect scopes.
|
||||
const ( |
||||
// OpenIDScope shows on the work account consent page as the "Sign you in" permission, and on the personal Microsoft
|
||||
// account consent page as the "View your profile and connect to apps and services using your Microsoft account"
|
||||
// permission. With this permission, an app can receive a unique identifier for the user in the form of the sub
|
||||
// claim. It also gives the app access to the UserInfo endpoint. The openid scope can be used at the v2.0 token
|
||||
// endpoint to acquire ID tokens, which can be used to secure HTTP calls between different components of an app.
|
||||
OpenIDScope ScopeType = "openid" |
||||
|
||||
// EmailScope can be used with the openid scope and any others. It gives the app access to the user's primary
|
||||
// email address in the form of the email claim. The email claim is included in a token only if an email address is
|
||||
// associated with the user account, which is not always the case. If it uses the email scope, your app should be
|
||||
// prepared to handle a case in which the email claim does not exist in the token.
|
||||
EmailScope ScopeType = "email" |
||||
|
||||
// ProfileScope can be used with the openid scope and any others. It gives the app access to a substantial
|
||||
// amount of information about the user. The information it can access includes, but is not limited to, the user's
|
||||
// given name, surname, preferred username, and object ID. For a complete list of the profile claims available in
|
||||
// the id_tokens parameter for a specific user, see the v2.0 tokens reference:
|
||||
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-id-and-access-tokens.
|
||||
ProfileScope ScopeType = "profile" |
||||
|
||||
// OfflineAccessScope gives your app access to resources on behalf of the user for an extended time. On the work
|
||||
// account consent page, this scope appears as the "Access your data anytime" permission. On the personal Microsoft
|
||||
// account consent page, it appears as the "Access your info anytime" permission. When a user approves the
|
||||
// offline_access scope, your app can receive refresh tokens from the v2.0 token endpoint. Refresh tokens are
|
||||
// long-lived. Your app can get new access tokens as older ones expire.
|
||||
//
|
||||
// If your app does not request the offline_access scope, it won't receive refresh tokens. This means that when you
|
||||
// redeem an authorization code in the OAuth 2.0 authorization code flow, you'll receive only an access token from
|
||||
// the /token endpoint. The access token is valid for a short time. The access token usually expires in one hour.
|
||||
// At that point, your app needs to redirect the user back to the /authorize endpoint to get a new authorization
|
||||
// code. During this redirect, depending on the type of app, the user might need to enter their credentials again
|
||||
// or consent again to permissions.
|
||||
OfflineAccessScope ScopeType = "offline_access" |
||||
) |
||||
|
||||
// Calendar Permissions
|
||||
//
|
||||
// Calendars.Read.Shared and Calendars.ReadWrite.Shared are only valid for work or school accounts. All other
|
||||
// permissions are valid for both Microsoft accounts and work or school accounts.
|
||||
//
|
||||
// See also https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
|
||||
const ( |
||||
// CalendarsReadScope allows the app to read events in user calendars.
|
||||
CalendarsReadScope ScopeType = "Calendars.Read" |
||||
|
||||
// CalendarsReadSharedScope allows the app to read events in all calendars that the user can access, including
|
||||
// delegate and shared calendars.
|
||||
CalendarsReadSharedScope ScopeType = "Calendars.Read.Shared" |
||||
|
||||
// CalendarsReadWriteScope allows the app to create, read, update, and delete events in user calendars.
|
||||
CalendarsReadWriteScope ScopeType = "Calendars.ReadWrite" |
||||
|
||||
// CalendarsReadWriteSharedScope allows the app to create, read, update and delete events in all calendars the user
|
||||
// has permissions to access. This includes delegate and shared calendars.
|
||||
CalendarsReadWriteSharedScope ScopeType = "Calendars.ReadWrite.Shared" |
||||
) |
||||
|
||||
// Contacts Permissions
|
||||
//
|
||||
// Only the Contacts.Read and Contacts.ReadWrite delegated permissions are valid for Microsoft accounts.
|
||||
//
|
||||
// See also https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
|
||||
const ( |
||||
// ContactsReadScope allows the app to read contacts that the user has permissions to access, including the user's
|
||||
// own and shared contacts.
|
||||
ContactsReadScope ScopeType = "Contacts.Read" |
||||
|
||||
// ContactsReadSharedScope allows the app to read contacts that the user has permissions to access, including the
|
||||
// user's own and shared contacts.
|
||||
ContactsReadSharedScope ScopeType = "Contacts.Read.Shared" |
||||
|
||||
// ContactsReadWriteScope allows the app to create, read, update, and delete user contacts.
|
||||
ContactsReadWriteScope ScopeType = "Contacts.ReadWrite" |
||||
|
||||
// ContactsReadWriteSharedScope allows the app to create, read, update and delete contacts that the user has
|
||||
// permissions to, including the user's own and shared contacts.
|
||||
ContactsReadWriteSharedScope ScopeType = "Contacts.ReadWrite.Shared" |
||||
) |
||||
|
||||
// Device Permissions
|
||||
//
|
||||
// The Device.Read and Device.Command delegated permissions are valid only for personal Microsoft accounts.
|
||||
//
|
||||
// See also https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
|
||||
const ( |
||||
// DeviceReadScope allows the app to read a user's list of devices on behalf of the signed-in user.
|
||||
DeviceReadScope ScopeType = "Device.Read" |
||||
|
||||
// DeviceCommandScope allows the app to launch another app or communicate with another app on a user's device on
|
||||
// behalf of the signed-in user.
|
||||
DeviceCommandScope ScopeType = "Device.Command" |
||||
) |
||||
|
||||
// Directory Permissions
|
||||
//
|
||||
// Directory permissions are not supported on Microsoft accounts.
|
||||
//
|
||||
// Directory permissions provide the highest level of privilege for accessing directory resources such as User, Group,
|
||||
// and Device in an organization.
|
||||
//
|
||||
// They also exclusively control access to other directory resources like: organizational contacts, schema extension
|
||||
// APIs, Privileged Identity Management (PIM) APIs, as well as many of the resources and APIs listed under the Azure
|
||||
// Active Directory node in the v1.0 and beta API reference documentation. These include administrative units, directory
|
||||
// roles, directory settings, policy, and many more.
|
||||
//
|
||||
// The Directory.ReadWrite.All permission grants the following privileges:
|
||||
// - Full read of all directory resources (both declared properties and navigation properties)
|
||||
// - Create and update users
|
||||
// - Disable and enable users (but not company administrator)
|
||||
// - Set user alternative security id (but not administrators)
|
||||
// - Create and update groups
|
||||
// - Manage group memberships
|
||||
// - Update group owner
|
||||
// - Manage license assignments
|
||||
// - Define schema extensions on applications
|
||||
// - Note: No rights to reset user passwords
|
||||
// - Note: No rights to delete resources (including users or groups)
|
||||
// - Note: Specifically excludes create or update for resources not listed above. This includes: application,
|
||||
// oAauth2Permissiongrant, appRoleAssignment, device, servicePrincipal, organization, domains, and so on.
|
||||
//
|
||||
// See also https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
|
||||
const ( |
||||
// DirectoryReadAllScope allows the app to read data in your organization's directory, such as users, groups and
|
||||
// apps.
|
||||
//
|
||||
// Note: Users may consent to applications that require this permission if the application is registered in their
|
||||
// own organization’s tenant.
|
||||
//
|
||||
// requires admin consent
|
||||
DirectoryReadAllScope ScopeType = "Directory.Read.All" |
||||
|
||||
// DirectoryReadWriteAllScope allows the app to read and write data in your organization's directory, such as users,
|
||||
// and groups. It does not allow the app to delete users or groups, or reset user passwords.
|
||||
//
|
||||
// requires admin consent
|
||||
DirectoryReadWriteAllScope ScopeType = "Directory.ReadWrite.All" |
||||
|
||||
// DirectoryAccessAsUserAllScope allows the app to have the same access to information in the directory as the
|
||||
// signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
DirectoryAccessAsUserAllScope ScopeType = "Directory.AccessAsUser.All" |
||||
) |
||||
|
||||
// Education Administration Permissions
|
||||
const ( |
||||
// EduAdministrationReadScope allows the app to read education app settings on behalf of the user.
|
||||
//
|
||||
// requires admin consent
|
||||
EduAdministrationReadScope ScopeType = "EduAdministration.Read" |
||||
|
||||
// EduAdministrationReadWriteScope allows the app to manage education app settings on behalf of the user.
|
||||
//
|
||||
// requires admin consent
|
||||
EduAdministrationReadWriteScope ScopeType = "EduAdministration.ReadWrite" |
||||
|
||||
// EduAssignmentsReadBasicScope allows the app to read assignments without grades on behalf of the user
|
||||
//
|
||||
// requires admin consent
|
||||
EduAssignmentsReadBasicScope ScopeType = "EduAssignments.ReadBasic" |
||||
|
||||
// EduAssignmentsReadWriteBasicScope allows the app to read and write assignments without grades on behalf of the
|
||||
// user
|
||||
EduAssignmentsReadWriteBasicScope ScopeType = "EduAssignments.ReadWriteBasic" |
||||
|
||||
// EduAssignmentsReadScope allows the app to read assignments and their grades on behalf of the user
|
||||
//
|
||||
// requires admin consent
|
||||
EduAssignmentsReadScope ScopeType = "EduAssignments.Read" |
||||
|
||||
// EduAssignmentsReadWriteScope allows the app to read and write assignments and their grades on behalf of the user
|
||||
//
|
||||
// requires admin consent
|
||||
EduAssignmentsReadWriteScope ScopeType = "EduAssignments.ReadWrite" |
||||
|
||||
// EduRosteringReadBasicScope allows the app to read a limited subset of the data from the structure of schools and
|
||||
// classes in an organization's roster and education-specific information about users to be read on behalf of the
|
||||
// user.
|
||||
//
|
||||
// requires admin consent
|
||||
EduRosteringReadBasicScope ScopeType = "EduRostering.ReadBasic" |
||||
) |
||||
|
||||
// Files Permissions
|
||||
//
|
||||
// The Files.Read, Files.ReadWrite, Files.Read.All, and Files.ReadWrite.All delegated permissions are valid on both
|
||||
// personal Microsoft accounts and work or school accounts. Note that for personal accounts, Files.Read and
|
||||
// Files.ReadWrite also grant access to files shared with the signed-in user.
|
||||
//
|
||||
// The Files.Read.Selected and Files.ReadWrite.Selected delegated permissions are only valid on work or school accounts
|
||||
// and are only exposed for working with Office 365 file handlers (v1.0)
|
||||
// https://msdn.microsoft.com/office/office365/howto/using-cross-suite-apps. They should not be used for directly
|
||||
// calling Microsoft Graph APIs.
|
||||
//
|
||||
// The Files.ReadWrite.AppFolder delegated permission is only valid for personal accounts and is used for accessing the
|
||||
// App Root special folder https://dev.onedrive.com/misc/appfolder.htm with the OneDrive Get special folder
|
||||
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/drive_get_specialfolder Microsoft Graph API.
|
||||
const ( |
||||
// FilesReadScope allows the app to read the signed-in user's files.
|
||||
FilesReadScope ScopeType = "Files.Read" |
||||
|
||||
// FilesReadAllScope allows the app to read all files the signed-in user can access.
|
||||
FilesReadAllScope ScopeType = "Files.Read.All" |
||||
|
||||
// FilesReadWrite allows the app to read, create, update, and delete the signed-in user's files.
|
||||
FilesReadWriteScope ScopeType = "Files.ReadWrite" |
||||
|
||||
// FilesReadWriteAllScope allows the app to read, create, update, and delete all files the signed-in user can access.
|
||||
FilesReadWriteAllScope ScopeType = "Files.ReadWrite.All" |
||||
|
||||
// FilesReadWriteAppFolderScope allows the app to read, create, update, and delete files in the application's folder.
|
||||
FilesReadWriteAppFolderScope ScopeType = "Files.ReadWrite.AppFolder" |
||||
|
||||
// FilesReadSelectedScope allows the app to read files that the user selects. The app has access for several hours
|
||||
// after the user selects a file.
|
||||
//
|
||||
// preview
|
||||
FilesReadSelectedScope ScopeType = "Files.Read.Selected" |
||||
|
||||
// FilesReadWriteSelectedScope allows the app to read and write files that the user selects. The app has access for
|
||||
// several hours after the user selects a file
|
||||
//
|
||||
// preview
|
||||
FilesReadWriteSelectedScope ScopeType = "Files.ReadWrite.Selected" |
||||
) |
||||
|
||||
// Group Permissions
|
||||
//
|
||||
// Group functionality is not supported on personal Microsoft accounts.
|
||||
//
|
||||
// For Office 365 groups, Group permissions grant the app access to the contents of the group; for example,
|
||||
// conversations, files, notes, and so on.
|
||||
//
|
||||
// For application permissions, there are some limitations for the APIs that are supported. For more information, see
|
||||
// known issues.
|
||||
//
|
||||
// In some cases, an app may need Directory permissions to read some group properties like member and memberOf. For
|
||||
// example, if a group has a one or more servicePrincipals as members, the app will need effective permissions to read
|
||||
// service principals through being granted one of the Directory.* permissions, otherwise Microsoft Graph will return an
|
||||
// error. (In the case of delegated permissions, the signed-in user will also need sufficient privileges in the
|
||||
// organization to read service principals.) The same guidance applies for the memberOf property, which can return
|
||||
// administrativeUnits.
|
||||
//
|
||||
// Group permissions are also used to control access to Microsoft Planner resources and APIs. Only delegated permissions
|
||||
// are supported for Microsoft Planner APIs; application permissions are not supported. Personal Microsoft accounts are
|
||||
// not supported.
|
||||
const ( |
||||
// GroupReadAllScope allows the app to list groups, and to read their properties and all group memberships on behalf
|
||||
// of the signed-in user. Also allows the app to read calendar, conversations, files, and other group content for
|
||||
// all groups the signed-in user can access.
|
||||
GroupReadAllScope ScopeType = "Group.Read.All" |
||||
|
||||
// GroupReadWriteAllScope allows the app to create groups and read all group properties and memberships on behalf of
|
||||
// the signed-in user. Additionally allows group owners to manage their groups and allows group members to update
|
||||
// group content.
|
||||
GroupReadWriteAllScope ScopeType = "Group.ReadWrite.All" |
||||
) |
||||
|
||||
// Identity Risk Event Permissions
|
||||
//
|
||||
// IdentityRiskEvent.Read.All is valid only for work or school accounts. For an app with delegated permissions to read
|
||||
// identity risk information, the signed-in user must be a member of one of the following administrator roles: Global
|
||||
// Administrator, Security Administrator, or Security Reader. For more information about administrator roles, see
|
||||
// Assigning administrator roles in Azure Active Directory.
|
||||
const ( |
||||
// IdentityRiskEventReadAllScope allows the app to read identity risk event information for all users in your
|
||||
// organization on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
IdentityRiskEventReadAllScope ScopeType = "IdentityRiskEvent.Read.All" |
||||
) |
||||
|
||||
// Identity Provider Permissions
|
||||
//
|
||||
// IdentityProvider.Read.All and IdentityProvider.ReadWrite.All are valid only for work or school accounts. For an app
|
||||
// to read or write identity providers with delegated permissions, the signed-in user must be assigned the Global
|
||||
// Administrator role. For more information about administrator roles, see Assigning administrator roles in Azure Active
|
||||
// Directory.
|
||||
const ( |
||||
// IdentityProviderReadAllScope allows the app to read identity providers configured in your Azure AD or Azure AD
|
||||
// B2C tenant on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
IdentityProviderReadAllScope ScopeType = "IdentityProvider.Read.All" |
||||
|
||||
// IdentityProviderReadWriteAllScope allows the app to read or write identity providers configured in your Azure AD
|
||||
// or Azure AD B2C tenant on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
IdentityProviderReadWriteAllScope ScopeType = "IdentityProvider.ReadWrite.All" |
||||
) |
||||
|
||||
// Device Management Permissions
|
||||
//
|
||||
// Using the Microsoft Graph APIs to configure Intune controls and policies still requires that the Intune service is
|
||||
// correctly licensed by the customer.
|
||||
//
|
||||
// These permissions are only valid for work or school accounts.
|
||||
const ( |
||||
// DeviceManagementAppsReadAllScope allows the app to read the properties, group assignments and status of apps, app
|
||||
// configurations and app protection policies managed by Microsoft Intune.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementAppsReadAllScope ScopeType = "DeviceManagementApps.Read.All" |
||||
|
||||
// DeviceManagementAppsReadWriteAllScope allows the app to read and write the properties, group assignments and
|
||||
// status of apps, app configurations and app protection policies managed by Microsoft Intune.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementAppsReadWriteAllScope ScopeType = "DeviceManagementApps.ReadWrite.All" |
||||
|
||||
// DeviceManagementConfigurationReadAllScope allows the app to read properties of Microsoft Intune-managed device
|
||||
// configuration and device compliance policies and their assignment to groups.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementConfigurationReadAllScope ScopeType = "DeviceManagementConfiguration.Read.All" |
||||
|
||||
// DeviceManagementConfigurationReadWriteAllScope allows the app to read and write properties of Microsoft
|
||||
// Intune-managed device configuration and device compliance policies and their assignment to groups.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementConfigurationReadWriteAllScope ScopeType = "DeviceManagementConfiguration.ReadWrite.All" |
||||
|
||||
// DeviceManagementManagedDevicesPrivilegedOperationsAllScope allows the app to perform remote high impact actions
|
||||
// such as wiping the device or resetting the passcode on devices managed by Microsoft Intune.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementManagedDevicesPrivilegedOperationsAllScope ScopeType = "DeviceManagementManagedDevices.PrivilegedOperations.All" |
||||
|
||||
// DeviceManagementManagedDevicesReadAllScope allows the app to read the properties of devices managed by Microsoft
|
||||
// Intune.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementManagedDevicesReadAllScope ScopeType = "DeviceManagementManagedDevices.Read.All" |
||||
|
||||
// DeviceManagementManagedDevicesReadWriteAllScope allows the app to read and write the properties of devices
|
||||
// managed by Microsoft Intune. Does not allow high impact operations such as remote wipe and password reset on the
|
||||
// device’s owner.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementManagedDevicesReadWriteAllScope ScopeType = "DeviceManagementManagedDevices.ReadWrite.All" |
||||
|
||||
// DeviceManagementRBACReadAllScope allows the app to read the properties relating to the Microsoft Intune
|
||||
// Role-Based Access Control (RBAC) settings.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementRBACReadAllScope ScopeType = "DeviceManagementRBAC.Read.All" |
||||
|
||||
// DeviceManagementRBACReadWriteAllScope allows the app to read and write the properties relating to the Microsoft
|
||||
// Intune Role-Based Access Control (RBAC) settings.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementRBACReadWriteAllScope ScopeType = "DeviceManagementRBAC.ReadWrite.All" |
||||
|
||||
// DeviceManagementServiceConfigReadAllScope allows the app to read Intune service properties including device
|
||||
// enrollment and third party service connection configuration.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementServiceConfigReadAllScope ScopeType = "DeviceManagementServiceConfig.Read.All" |
||||
|
||||
// DeviceManagementServiceConfigReadWriteAllScope allows the app to read and write Microsoft Intune service
|
||||
// properties including device enrollment and third party service connection configuration.
|
||||
//
|
||||
// requires admin consent
|
||||
DeviceManagementServiceConfigReadWriteAllScope ScopeType = "DeviceManagementServiceConfig.ReadWrite.All" |
||||
) |
||||
|
||||
// Mail Permissions
|
||||
//
|
||||
// Mail.Read.Shared, Mail.ReadWrite.Shared, and Mail.Send.Shared are only valid for work or school accounts. All other
|
||||
// permissions are valid for both Microsoft accounts and work or school accounts.
|
||||
//
|
||||
// With the Mail.Send or Mail.Send.Shared permission, an app can send mail and save a copy to the user's Sent Items
|
||||
// folder, even if the app does not use a corresponding Mail.ReadWrite or Mail.ReadWrite.Shared permission.
|
||||
const ( |
||||
// MailReadScope allows the app to read email in user mailboxes.
|
||||
MailReadScope ScopeType = "Mail.Read" |
||||
|
||||
// MailReadWriteScope allows the app to create, read, update, and delete email in user mailboxes. Does not include
|
||||
// permission to send mail.
|
||||
MailReadWriteScope ScopeType = "Mail.ReadWrite" |
||||
|
||||
// MailReadSharedScope allows the app to read mail that the user can access, including the user's own and shared
|
||||
// mail.
|
||||
MailReadSharedScope ScopeType = "Mail.Read.Shared" |
||||
|
||||
// MailReadWriteSharedScope allows the app to create, read, update, and delete mail that the user has permission to
|
||||
// access, including the user's own and shared mail. Does not include permission to send mail.
|
||||
MailReadWriteSharedScope ScopeType = "Mail.ReadWrite.Shared" |
||||
|
||||
// MailSend allowsScope the app to send mail as users in the organization.
|
||||
MailSendScope ScopeType = "Mail.Send" |
||||
|
||||
// MailSendSharedScope allows the app to send mail as the signed-in user, including sending on-behalf of others.
|
||||
MailSendSharedScope ScopeType = "Mail.Send.Shared" |
||||
|
||||
// MailboxSettingsReadScope allows the app to the read user's mailbox settings. Does not include permission to send
|
||||
// mail.
|
||||
MailboxSettingsReadScope ScopeType = "Mailbox.Settings.Read" |
||||
|
||||
// MailboxSettingsReadWriteScope allows the app to create, read, update, and delete user's mailbox settings. Does
|
||||
// not include permission to directly send mail, but allows the app to create rules that can forward or redirect
|
||||
// messages.
|
||||
MailboxSettingsReadWriteScope ScopeType = "MailboxSettings.ReadWrite" |
||||
) |
||||
|
||||
// Member Permissions
|
||||
//
|
||||
// Member.Read.Hidden is valid only on work or school accounts.
|
||||
//
|
||||
// Membership in some Office 365 groups can be hidden. This means that only the members of the group can view its
|
||||
// members. This feature can be used to help comply with regulations that require an organization to hide group
|
||||
// membership from outsiders (for example, an Office 365 group that represents students enrolled in a class).
|
||||
const ( |
||||
// MemberReadHiddenScope allows the app to read the memberships of hidden groups and administrative units on behalf
|
||||
// of the signed-in user, for those hidden groups and administrative units that the signed-in user has access to.
|
||||
//
|
||||
// requires admin consent
|
||||
MemberReadHiddenScope ScopeType = "Member.Read.Hidden" |
||||
) |
||||
|
||||
// Notes Permissions
|
||||
//
|
||||
// Notes.Read.All and Notes.ReadWrite.All are only valid for work or school accounts. All other permissions are valid
|
||||
// for both Microsoft accounts and work or school accounts.
|
||||
//
|
||||
// With the Notes.Create permission, an app can view the OneNote notebook hierarchy of the signed-in user and create
|
||||
// OneNote content (notebooks, section groups, sections, pages, etc.).
|
||||
//
|
||||
// Notes.ReadWrite and Notes.ReadWrite.All also allow the app to modify the permissions on the OneNote content that can
|
||||
// be accessed by the signed-in user.
|
||||
//
|
||||
// For work or school accounts, Notes.Read.All and Notes.ReadWrite.All allow the app to access other users' OneNote
|
||||
// content that the signed-in user has permission to within the organization.
|
||||
const ( |
||||
// NotesReadScope allows the app to read OneNote notebooks on behalf of the signed-in user.
|
||||
NotesReadScope ScopeType = "Notes.Read" |
||||
|
||||
// NotesCreateScope allows the app to read the titles of OneNote notebooks and sections and to create new pages,
|
||||
// notebooks, and sections on behalf of the signed-in user.
|
||||
NotesCreateScope ScopeType = "Notes.Create" |
||||
|
||||
// NotesReadWriteScope allows the app to read, share, and modify OneNote notebooks on behalf of the signed-in user.
|
||||
NotesReadWriteScope ScopeType = "Notes.ReadWrite" |
||||
|
||||
// NotesReadAllScope allows the app to read OneNote notebooks that the signed-in user has access to in the
|
||||
// organization.
|
||||
NotesReadAllScope ScopeType = "Notes.Read.All" |
||||
|
||||
// NotesReadWriteAllScope allows the app to read, share, and modify OneNote notebooks that the signed-in user has
|
||||
// access to in the organization.
|
||||
NotesReadWriteAllScope ScopeType = "Notes.ReadWrite.All" |
||||
) |
||||
|
||||
// People Permissions
|
||||
//
|
||||
// The People.Read.All permission is only valid for work and school accounts.
|
||||
const ( |
||||
// PeopleReadScope allows the app to read a scored list of people relevant to the signed-in user. The list can
|
||||
// include local contacts, contacts from social networking or your organization's directory, and people from recent
|
||||
// communications (such as email and Skype).
|
||||
PeopleReadScope ScopeType = "People.Read" |
||||
|
||||
// PeopleReadAllScope allows the app to read a scored list of people relevant to the signed-in user or other users
|
||||
// in the signed-in user's organization. The list can include local contacts, contacts from social networking or
|
||||
// your organization's directory, and people from recent communications (such as email and Skype). Also allows the
|
||||
// app to search the entire directory of the signed-in user's organization.
|
||||
//
|
||||
// requires admin consent
|
||||
PeopleReadAllScope ScopeType = "People.Read.All" |
||||
) |
||||
|
||||
// Report Permissions
|
||||
//
|
||||
// Reports permissions are only valid for work or school accounts.
|
||||
const ( |
||||
// ReportsReadAllScope allows an app to read all service usage reports without a signed-in user. Services that
|
||||
// provide usage reports include Office 365 and Azure Active Directory.
|
||||
//
|
||||
// requires admin consent
|
||||
ReportsReadAllScope ScopeType = "Reports.Read.All" |
||||
) |
||||
|
||||
// Security Permissions
|
||||
//
|
||||
// Security permissions are valid only on work or school accounts.
|
||||
const ( |
||||
// SecurityEventsReadAllScope allows the app to read your organization’s security events on behalf of the signed-in
|
||||
// user.
|
||||
// requires admin consent
|
||||
SecurityEventsReadAllScope ScopeType = "SecurityEvents.Read.All" |
||||
|
||||
// SecurityEventsReadWriteAllScope allows the app to read your organization’s security events on behalf of the
|
||||
// signed-in user. Also allows the app to update editable properties in security events on behalf of the signed-in
|
||||
// user.
|
||||
//
|
||||
// requires admin consent
|
||||
SecurityEventsReadWriteAllScope ScopeType = "SecurityEvents.ReadWrite.All" |
||||
) |
||||
|
||||
// Sites Permissions
|
||||
//
|
||||
// Sites permissions are valid only on work or school accounts.
|
||||
const ( |
||||
// SitesReadAllScope allows the app to read documents and list items in all site collections on behalf of the
|
||||
// signed-in user.
|
||||
SitesReadAllScope ScopeType = "Sites.Read.All" |
||||
|
||||
// SitesReadWriteAllScope allows the app to edit or delete documents and list items in all site collections on
|
||||
// behalf of the signed-in user.
|
||||
SitesReadWriteAllScope ScopeType = "Sites.ReadWrite.All" |
||||
|
||||
// SitesManageAllScope allows the app to manage and create lists, documents, and list items in all site collections
|
||||
// on behalf of the signed-in user.
|
||||
SitesManageAllScope ScopeType = "Sites.Manage.All" |
||||
|
||||
// SitesFullControlAllScope allows the app to have full control to SharePoint sites in all site collections on
|
||||
// behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
SitesFullControlAllScope ScopeType = "Sites.FullControl.All" |
||||
) |
||||
|
||||
// Tasks Permissions
|
||||
//
|
||||
// Tasks permissions are used to control access for Outlook tasks. Access for Microsoft Planner tasks is controlled by
|
||||
// Group permissions.
|
||||
//
|
||||
// Shared permissions are currently only supported for work or school accounts. Even with Shared permissions, reads and
|
||||
// writes may fail if the user who owns the shared content has not granted the accessing user permissions to modify
|
||||
// content within the folder.
|
||||
const ( |
||||
// TasksReadScope allows the app to read user tasks.
|
||||
TasksReadScope ScopeType = "Tasks.Read" |
||||
|
||||
// TasksReadSharedScope allows the app to read tasks a user has permissions to access, including their own and
|
||||
// shared tasks.
|
||||
TasksReadSharedScope ScopeType = "Tasks.Read.Shared" |
||||
|
||||
// TasksReadWriteScope allows the app to create, read, update and delete tasks and containers (and tasks in them)
|
||||
// that are assigned to or shared with the signed-in user.
|
||||
TasksReadWriteScope ScopeType = "Tasks.ReadWrite" |
||||
|
||||
// TasksReadWriteSharedScope allows the app to create, read, update, and delete tasks a user has permissions to,
|
||||
// including their own and shared tasks.
|
||||
TasksReadWriteSharedScope ScopeType = "Tasks.ReadWrite.Shared" |
||||
) |
||||
|
||||
// Terms of Use Permissions
|
||||
//
|
||||
// All the permissions above are valid only for work or school accounts.
|
||||
//
|
||||
// For an app to read or write all agreements or agreement acceptances with delegated permissions, the signed-in user
|
||||
// must be assigned the Global Administrator, Conditional Access Administrator or Security Administrator role. For more
|
||||
// information about administrator roles, see Assigning administrator roles in Azure Active Directory
|
||||
// https://docs.microsoft.com/azure/active-directory/active-directory-assign-admin-roles.
|
||||
const ( |
||||
// AgreementReadAllScope allows the app to read terms of use agreements on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
AgreementReadAllScope ScopeType = "Agreement.Read.All" |
||||
|
||||
// AgreementReadWriteAllScope allows the app to read and write terms of use agreements on behalf of the signed-in
|
||||
// user.
|
||||
//
|
||||
// requires admin consent
|
||||
AgreementReadWriteAllScope ScopeType = "Agreement.ReadWrite.All" |
||||
|
||||
// AgreementAcceptanceReadScope allows the app to read terms of use acceptance statuses on behalf of the signed-in
|
||||
// user.
|
||||
//
|
||||
// requires admin consent
|
||||
AgreementAcceptanceReadScope ScopeType = "AgreementAcceptance.Read" |
||||
|
||||
// AgreementAcceptanceReadAllScope allows the app to read terms of use acceptance statuses on behalf of the
|
||||
// signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
AgreementAcceptanceReadAllScope ScopeType = "AgreementAcceptance.Read.All" |
||||
) |
||||
|
||||
// User Permissions
|
||||
//
|
||||
// The only permissions valid for Microsoft accounts are User.Read and User.ReadWrite. For work or school accounts, all
|
||||
// permissions are valid.
|
||||
//
|
||||
// With the User.Read permission, an app can also read the basic company information of the signed-in user for a work or
|
||||
// school account through the organization resource. The following properties are available: id, displayName, and
|
||||
// verifiedDomains.
|
||||
//
|
||||
// For work or school accounts, the full profile includes all of the declared properties of the User resource. On reads,
|
||||
// only a limited number of properties are returned by default. To read properties that are not in the default set, use
|
||||
// $select. The default properties are:
|
||||
// displayName
|
||||
// givenName
|
||||
// jobTitle
|
||||
// mail
|
||||
// mobilePhone
|
||||
// officeLocation
|
||||
// preferredLanguage
|
||||
// surname
|
||||
// userPrincipalName
|
||||
//
|
||||
// User.ReadWrite and User.Readwrite.All delegated permissions allow the app to update the following profile properties
|
||||
// for work or school accounts:
|
||||
// aboutMe
|
||||
// birthday
|
||||
// hireDate
|
||||
// interests
|
||||
// mobilePhone
|
||||
// mySite
|
||||
// pastProjects
|
||||
// photo
|
||||
// preferredName
|
||||
// responsibilities
|
||||
// schools
|
||||
// skills
|
||||
//
|
||||
// With the User.ReadWrite.All application permission, the app can update all of the declared properties of work or
|
||||
// school accounts except for password.
|
||||
//
|
||||
// To read or write direct reports (directReports) or the manager (manager) of a work or school account, the app must
|
||||
// have either User.Read.All (read only) or User.ReadWrite.All.
|
||||
//
|
||||
// The User.ReadBasic.All permission constrains app access to a limited set of properties known as the basic profile.
|
||||
// This is because the full profile might contain sensitive directory information. The basic profile includes only the
|
||||
// following properties:
|
||||
// displayName
|
||||
// givenName
|
||||
// mail
|
||||
// photo
|
||||
// surname
|
||||
// userPrincipalName
|
||||
//
|
||||
// To read the group memberships of a user (memberOf), the app must have either Group.Read.All or Group.ReadWrite.All.
|
||||
// However, if the user also has membership in a directoryRole or an administrativeUnit, the app will need effective
|
||||
// permissions to read those resources too, or Microsoft Graph will return an error. This means the app will also need
|
||||
// Directory permissions, and, for delegated permissions, the signed-in user will also need sufficient privileges in the
|
||||
// organization to access directory roles and administrative units.
|
||||
const ( |
||||
// UserReadScope allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It
|
||||
// also allows the app to read basic company information of signed-in users.
|
||||
UserReadScope ScopeType = "User.Read" |
||||
|
||||
// UserReadWriteScope allows the app to read the signed-in user's full profile. It also allows the app to update the
|
||||
// signed-in user's profile information on their behalf.
|
||||
UserReadWriteScope ScopeType = "User.ReadWrite" |
||||
|
||||
// UserReadBasicAllScope allows the app to read a basic set of profile properties of other users in your
|
||||
// organization on behalf of the signed-in user. This includes display name, first and last name, email address,
|
||||
// open extensions and photo. Also allows the app to read the full profile of the signed-in user.
|
||||
UserReadBasicAllScope ScopeType = "User.ReadBasic.All" |
||||
|
||||
// UserReadAllScope allows the app to read the full set of profile properties, reports, and managers of other users
|
||||
// in your organization, on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
UserReadAllScope ScopeType = "User.Read.All" |
||||
|
||||
// UserReadWriteAllScope allows the app to read and write the full set of profile properties, reports, and managers
|
||||
// of other users in your organization, on behalf of the signed-in user. Also allows the app to create and delete
|
||||
// users as well as reset user passwords on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
UserReadWriteAllScope ScopeType = "User.ReadWrite.All" |
||||
|
||||
// UserInviteAllScope allows the app to invite guest users to your organization, on behalf of the signed-in user.
|
||||
//
|
||||
// requires admin consent
|
||||
UserInviteAllScope ScopeType = "User.Invite.All" |
||||
|
||||
// UserExportAllScope allows the app to export an organizational user's data, when performed by a Company
|
||||
// Administrator.
|
||||
//
|
||||
// requires admin consent
|
||||
UserExportAllScope ScopeType = "User.Export.All" |
||||
) |
||||
|
||||
// User Activity Permissions
|
||||
//
|
||||
// UserActivity.ReadWrite.CreatedByApp is valid for both Microsoft accounts and work or school accounts.
|
||||
//
|
||||
// The CreatedByApp constraint associated with this permission indicates the service will apply implicit filtering to
|
||||
// results based on the identity of the calling app, either the MSA app id or a set of app ids configured for a
|
||||
// cross-platform application identity.
|
||||
const ( |
||||
// UserActivityReadWriteCreatedByAppScope allows the app to read and report the signed-in user's activity in the
|
||||
// app.
|
||||
UserActivityReadWriteCreatedByAppScope ScopeType = "UserActivity.ReadWrite.CreatedByApp" |
||||
) |
@ -0,0 +1,63 @@ |
||||
package azureadv2 |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/markbates/goth" |
||||
) |
||||
|
||||
// Session is the implementation of `goth.Session`
|
||||
type Session struct { |
||||
AuthURL string `json:"au"` |
||||
AccessToken string `json:"at"` |
||||
RefreshToken string `json:"rt"` |
||||
ExpiresAt time.Time `json:"exp"` |
||||
} |
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` func
|
||||
func (s Session) GetAuthURL() (string, error) { |
||||
if s.AuthURL == "" { |
||||
return "", errors.New(goth.NoAuthUrlErrorMessage) |
||||
} |
||||
|
||||
return s.AuthURL, nil |
||||
} |
||||
|
||||
// Authorize the session with AzureAD and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) { |
||||
p := provider.(*Provider) |
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code")) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !token.Valid() { |
||||
return "", errors.New("invalid token received from provider") |
||||
} |
||||
|
||||
s.AccessToken = token.AccessToken |
||||
s.RefreshToken = token.RefreshToken |
||||
s.ExpiresAt = token.Expiry |
||||
|
||||
return token.AccessToken, err |
||||
} |
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string { |
||||
b, _ := json.Marshal(s) |
||||
return string(b) |
||||
} |
||||
|
||||
func (s Session) String() string { |
||||
return s.Marshal() |
||||
} |
||||
|
||||
// UnmarshalSession wil unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { |
||||
session := &Session{} |
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(session) |
||||
return session, err |
||||
} |
190
vendor/github.com/markbates/goth/providers/microsoftonline/microsoftonline.go
generated
vendored
190
vendor/github.com/markbates/goth/providers/microsoftonline/microsoftonline.go
generated
vendored
@ -0,0 +1,190 @@ |
||||
// Package microsoftonline implements the OAuth2 protocol for authenticating users through microsoftonline.
|
||||
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
|
||||
// To use this package, your application need to be registered in [Application Registration Portal](https://apps.dev.microsoft.com/)
|
||||
package microsoftonline |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"net/http" |
||||
|
||||
"github.com/markbates/going/defaults" |
||||
"github.com/markbates/goth" |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
const ( |
||||
authURL string = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" |
||||
tokenURL string = "https://login.microsoftonline.com/common/oauth2/v2.0/token" |
||||
endpointProfile string = "https://graph.microsoft.com/v1.0/me" |
||||
) |
||||
|
||||
var defaultScopes = []string{"openid", "offline_access", "user.read"} |
||||
|
||||
// New creates a new microsoftonline provider, and sets up important connection details.
|
||||
// You should always call `microsoftonline.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider { |
||||
p := &Provider{ |
||||
ClientKey: clientKey, |
||||
Secret: secret, |
||||
CallbackURL: callbackURL, |
||||
providerName: "microsoftonline", |
||||
} |
||||
|
||||
p.config = newConfig(p, scopes) |
||||
return p |
||||
} |
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing microsoftonline.
|
||||
type Provider struct { |
||||
ClientKey string |
||||
Secret string |
||||
CallbackURL string |
||||
HTTPClient *http.Client |
||||
config *oauth2.Config |
||||
providerName string |
||||
tenant string |
||||
} |
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string { |
||||
return p.providerName |
||||
} |
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) { |
||||
p.providerName = name |
||||
} |
||||
|
||||
// Client is HTTP client to be used in all fetch operations.
|
||||
func (p *Provider) Client() *http.Client { |
||||
return goth.HTTPClientWithFallBack(p.HTTPClient) |
||||
} |
||||
|
||||
// Debug is a no-op for the facebook package.
|
||||
func (p *Provider) Debug(debug bool) {} |
||||
|
||||
// BeginAuth asks MicrosoftOnline for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) { |
||||
authURL := p.config.AuthCodeURL(state) |
||||
return &Session{ |
||||
AuthURL: authURL, |
||||
}, nil |
||||
} |
||||
|
||||
// FetchUser will go to MicrosoftOnline and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { |
||||
msSession := session.(*Session) |
||||
user := goth.User{ |
||||
AccessToken: msSession.AccessToken, |
||||
Provider: p.Name(), |
||||
ExpiresAt: msSession.ExpiresAt, |
||||
} |
||||
|
||||
if user.AccessToken == "" { |
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) |
||||
} |
||||
|
||||
req, err := http.NewRequest("GET", endpointProfile, nil) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
|
||||
req.Header.Set(authorizationHeader(msSession)) |
||||
|
||||
response, err := p.Client().Do(req) |
||||
if err != nil { |
||||
return user, err |
||||
} |
||||
defer response.Body.Close() |
||||
|
||||
if response.StatusCode != http.StatusOK { |
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode) |
||||
} |
||||
|
||||
user.AccessToken = msSession.AccessToken |
||||
|
||||
err = userFromReader(response.Body, &user) |
||||
return user, err |
||||
} |
||||
|
||||
// RefreshTokenAvailable refresh token is provided by auth provider or not
|
||||
// not available for microsoft online as session size hit the limit of max cookie size
|
||||
func (p *Provider) RefreshTokenAvailable() bool { |
||||
return false |
||||
} |
||||
|
||||
//RefreshToken get new access token based on the refresh token
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) { |
||||
if refreshToken == "" { |
||||
return nil, fmt.Errorf("No refresh token provided") |
||||
} |
||||
|
||||
token := &oauth2.Token{RefreshToken: refreshToken} |
||||
ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token) |
||||
newToken, err := ts.Token() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return newToken, err |
||||
} |
||||
|
||||
func newConfig(provider *Provider, scopes []string) *oauth2.Config { |
||||
c := &oauth2.Config{ |
||||
ClientID: provider.ClientKey, |
||||
ClientSecret: provider.Secret, |
||||
RedirectURL: provider.CallbackURL, |
||||
Endpoint: oauth2.Endpoint{ |
||||
AuthURL: authURL, |
||||
TokenURL: tokenURL, |
||||
}, |
||||
Scopes: []string{}, |
||||
} |
||||
|
||||
c.Scopes = append(c.Scopes, scopes...) |
||||
if len(scopes) == 0 { |
||||
c.Scopes = append(c.Scopes, defaultScopes...) |
||||
} |
||||
|
||||
return c |
||||
} |
||||
|
||||
func userFromReader(r io.Reader, user *goth.User) error { |
||||
buf := &bytes.Buffer{} |
||||
tee := io.TeeReader(r, buf) |
||||
|
||||
u := struct { |
||||
ID string `json:"id"` |
||||
Name string `json:"displayName"` |
||||
Email string `json:"mail"` |
||||
FirstName string `json:"givenName"` |
||||
LastName string `json:"surname"` |
||||
UserPrincipalName string `json:"userPrincipalName"` |
||||
}{} |
||||
|
||||
if err := json.NewDecoder(tee).Decode(&u); err != nil { |
||||
return err |
||||
} |
||||
|
||||
raw := map[string]interface{}{} |
||||
if err := json.NewDecoder(buf).Decode(&raw); err != nil { |
||||
return err |
||||
} |
||||
|
||||
user.UserID = u.ID |
||||
user.Email = defaults.String(u.Email, u.UserPrincipalName) |
||||
user.Name = u.Name |
||||
user.NickName = u.Name |
||||
user.FirstName = u.FirstName |
||||
user.LastName = u.LastName |
||||
user.RawData = raw |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func authorizationHeader(session *Session) (string, string) { |
||||
return "Authorization", fmt.Sprintf("Bearer %s", session.AccessToken) |
||||
} |
@ -0,0 +1,62 @@ |
||||
package microsoftonline |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/markbates/goth" |
||||
) |
||||
|
||||
// Session is the implementation of `goth.Session` for accessing microsoftonline.
|
||||
// Refresh token not available for microsoft online: session size hit the limit of max cookie size
|
||||
type Session struct { |
||||
AuthURL string |
||||
AccessToken string |
||||
ExpiresAt time.Time |
||||
} |
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Facebook provider.
|
||||
func (s Session) GetAuthURL() (string, error) { |
||||
if s.AuthURL == "" { |
||||
return "", errors.New(goth.NoAuthUrlErrorMessage) |
||||
} |
||||
|
||||
return s.AuthURL, nil |
||||
} |
||||
|
||||
// Authorize the session with Facebook and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) { |
||||
p := provider.(*Provider) |
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code")) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !token.Valid() { |
||||
return "", errors.New("Invalid token received from provider") |
||||
} |
||||
|
||||
s.AccessToken = token.AccessToken |
||||
s.ExpiresAt = token.Expiry |
||||
|
||||
return token.AccessToken, err |
||||
} |
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string { |
||||
b, _ := json.Marshal(s) |
||||
return string(b) |
||||
} |
||||
|
||||
func (s Session) String() string { |
||||
return s.Marshal() |
||||
} |
||||
|
||||
// UnmarshalSession wil unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { |
||||
session := &Session{} |
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(session) |
||||
return session, err |
||||
} |
Loading…
Reference in new issue