add microsoft auth
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments.
|
||||
|
||||
* Social login via Google, Twitter, Facebook, GitHub and Yandex
|
||||
* Social login via Google, Twitter, Facebook, Microsoft, GitHub and Yandex
|
||||
* Login via email
|
||||
* Optional anonymous access
|
||||
* Multi-level nested comments with both tree and plain presentations
|
||||
@@ -135,6 +135,8 @@ _this is the recommended way to run remark42_
|
||||
| auth.google.csec | AUTH_GOOGLE_CSEC | | Google OAuth client secret |
|
||||
| auth.facebook.cid | AUTH_FACEBOOK_CID | | Facebook OAuth client ID |
|
||||
| auth.facebook.csec | AUTH_FACEBOOK_CSEC | | Facebook OAuth client secret |
|
||||
| auth.microsoft.cid | AUTH_MICROSOFT_CID | | Microsoft OAuth client ID |
|
||||
| auth.microsoft.csec | AUTH_MICROSOFT_CSEC | | Microsoft OAuth client secret |
|
||||
| auth.github.cid | AUTH_GITHUB_CID | | Github OAuth client ID |
|
||||
| auth.github.csec | AUTH_GITHUB_CSEC | | Github OAuth client secret |
|
||||
| auth.twitter.cid | AUTH_TWITTER_CID | | Twitter Consumer API Key |
|
||||
@@ -284,6 +286,14 @@ _instructions for google oauth2 setup borrowed from [oauth2_proxy](https://githu
|
||||
1. Under **"Facebook login"** / **"Settings"** fill "Valid OAuth redirect URIs" with your callback url constructed as domain + `/auth/facebook/callback`
|
||||
1. Select **"App Review"** and turn public flag on. This step may ask you to provide a link to your privacy policy.
|
||||
|
||||
#### Microsoft Auth Provider
|
||||
|
||||
1. Register a new application [using the Azure portal](https://docs.microsoft.com/en-us/graph/auth-register-app-v2).
|
||||
2. Under **"Authentication/Platform configurations/Web"** enter the correct url constructed as domain + `/auth/microsoft/callback`. i.e. `https://example.mysite.com/auth/microsoft/callback`
|
||||
3. In "Overview" take note of the **Application (client) ID**
|
||||
4. Choose the new project from the top right project dropdown (only if another project is selected)
|
||||
5. Select "Certificates & secrets" and click on "+ New Client Secret".
|
||||
|
||||
##### Twitter Auth Provider
|
||||
|
||||
1. Create a new twitter application https://developer.twitter.com/en/apps
|
||||
|
||||
@@ -83,6 +83,7 @@ type ServerCommand struct {
|
||||
Google AuthGroup `group:"google" namespace:"google" env-namespace:"GOOGLE" description:"Google OAuth"`
|
||||
Github AuthGroup `group:"github" namespace:"github" env-namespace:"GITHUB" description:"Github OAuth"`
|
||||
Facebook AuthGroup `group:"facebook" namespace:"facebook" env-namespace:"FACEBOOK" description:"Facebook OAuth"`
|
||||
Microsoft AuthGroup `group:"microsoft" namespace:"microsoft" env-namespace:"MICROSOFT" description:"Microsoft OAuth"`
|
||||
Yandex AuthGroup `group:"yandex" namespace:"yandex" env-namespace:"YANDEX" description:"Yandex OAuth"`
|
||||
Twitter AuthGroup `group:"twitter" namespace:"twitter" env-namespace:"TWITTER" description:"Twitter OAuth"`
|
||||
Dev bool `long:"dev" env:"DEV" description:"enable dev (local) oauth2"`
|
||||
@@ -697,6 +698,10 @@ func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) error {
|
||||
authenticator.AddProvider("facebook", s.Auth.Facebook.CID, s.Auth.Facebook.CSEC)
|
||||
providers++
|
||||
}
|
||||
if s.Auth.Microsoft.CID != "" && s.Auth.Microsoft.CSEC != "" {
|
||||
authenticator.AddProvider("microsoft", s.Auth.Microsoft.CID, s.Auth.Microsoft.CSEC)
|
||||
providers++
|
||||
}
|
||||
if s.Auth.Yandex.CID != "" && s.Auth.Yandex.CSEC != "" {
|
||||
authenticator.AddProvider("yandex", s.Auth.Yandex.CID, s.Auth.Yandex.CSEC)
|
||||
providers++
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ require (
|
||||
github.com/go-chi/chi v4.1.1+incompatible
|
||||
github.com/go-chi/cors v1.1.1
|
||||
github.com/go-chi/render v1.0.1
|
||||
github.com/go-pkgz/auth v0.10.2
|
||||
github.com/go-pkgz/auth v0.11.0
|
||||
github.com/go-pkgz/jrpc v0.2.0
|
||||
github.com/go-pkgz/lcw v0.6.1
|
||||
github.com/go-pkgz/lgr v0.7.0
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@ github.com/go-chi/cors v1.1.1 h1:eHuqxsIw89iXcWnWUN8R72JMibABJTN/4IOYI5WERvw=
|
||||
github.com/go-chi/cors v1.1.1/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
|
||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
||||
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
|
||||
github.com/go-pkgz/auth v0.10.2 h1:aYTEu0sxBi+UJXm3IIn9/cgW7bTXZkiykY23rdYZjAc=
|
||||
github.com/go-pkgz/auth v0.10.2/go.mod h1:w4Z1qaYvuh2P3T2gNh0f8GcKCH0HHAoQtQ8iv+9+WGg=
|
||||
github.com/go-pkgz/auth v0.11.0 h1:xi9Y0KGZUftVLx/8tGdvIfUk/+/4QLBVL6k9A8C4ycM=
|
||||
github.com/go-pkgz/auth v0.11.0/go.mod h1:NzVqlTW0E9JXVdAaWRq81XZjICgHnNaNdUfE3CbS2T4=
|
||||
github.com/go-pkgz/expirable-cache v0.0.3 h1:rTh6qNPp78z0bQE6HDhXBHUwqnV9i09Vm6dksJLXQDc=
|
||||
github.com/go-pkgz/expirable-cache v0.0.3/go.mod h1:+IauqN00R2FqNRLCLA+X5YljQJrwB179PfiAoMPlTlQ=
|
||||
github.com/go-pkgz/jrpc v0.2.0 h1:CLy/eZyekjraVrxZV18N2R1mYLMJ/nWrgdfyIOGPY/E=
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ linters-settings:
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
min-complexity: 20
|
||||
maligned:
|
||||
suggest-new: true
|
||||
goconst:
|
||||
|
||||
+30
-4
@@ -1,7 +1,7 @@
|
||||
# auth - authentication via oauth2, direct and email
|
||||
[](https://github.com/go-pkgz/auth/actions) [](https://coveralls.io/github/go-pkgz/auth?branch=master) [](https://pkg.go.dev/github.com/go-pkgz/auth?tab=doc)
|
||||
|
||||
This library provides "social login" with Github, Google, Facebook, Twitter and Yandex as well as custom auth providers and email verification.
|
||||
This library provides "social login" with Github, Google, Facebook, Microsoft, Twitter, Yandex and Battle.net as well as custom auth providers and email verification.
|
||||
|
||||
- Multiple oauth2 providers can be used at the same time
|
||||
- Special `dev` provider allows local testing and development
|
||||
@@ -78,6 +78,8 @@ func main() {
|
||||
- `middleware.Admin` - requires authenticated admin user
|
||||
- `middleware.Trace` - doesn't require authenticated user, but adds user info to request
|
||||
|
||||
Also, there is a special middleware `middleware.UpdateUser` for population and modifying UserInfo in every request. See "Customization" for more details.
|
||||
|
||||
## Details
|
||||
|
||||
Generally, adding support of `auth` includes a few relatively simple steps:
|
||||
@@ -249,10 +251,11 @@ In order to add a new oauth2 provider following input is required:
|
||||
There are several ways to adjust functionality of the library:
|
||||
|
||||
1. `SecretReader` - interface with a single method `Get(aud string) string` to return the secret used for JWT signing and verification
|
||||
2. `ClaimsUpdater` - interface with `Update(claims Claims) Claims` method. This is the primary way to alter a token at login time and add any attributes, set ip, email, admin status and so on.
|
||||
3. `Validator` - interface with `Validate(token string, claims Claims) bool` method. This is post-token hook and will be called on **each request** wrapped with `Auth` middleware. This will be the place for special logic to reject some tokens or users.
|
||||
1. `ClaimsUpdater` - interface with `Update(claims Claims) Claims` method. This is the primary way to alter a token at login time and add any attributes, set ip, email, admin status and so on.
|
||||
1. `Validator` - interface with `Validate(token string, claims Claims) bool` method. This is post-token hook and will be called on **each request** wrapped with `Auth` middleware. This will be the place for special logic to reject some tokens or users.
|
||||
1. `UserUpdater` - interface with `Update(claims token.User) token.User` method. This method will be called on **each request** wrapped with `UpdateUser` middleware. This will be the place for special logic modify User Info in request context. [Example of usage.]((https://github.com/go-pkgz/auth/blob/master/_example/main.go#L148))
|
||||
|
||||
All of the interfaces above have corresponding Func adapters - `SecretFunc`, `ClaimsUpdFunc` and `ValidatorFunc`.
|
||||
All of the interfaces above have corresponding Func adapters - `SecretFunc`, `ClaimsUpdFunc`, `ValidatorFunc` and `UserUpdFunc`.
|
||||
|
||||
### Implementing black list logic or some other filters
|
||||
|
||||
@@ -332,6 +335,15 @@ Authentication handled by external providers. You should setup oauth2 for all (o
|
||||
|
||||
_instructions for google oauth2 setup borrowed from [oauth2_proxy](https://github.com/bitly/oauth2_proxy)_
|
||||
|
||||
#### Microsoft Auth Provider
|
||||
|
||||
1 .Register a new application [using the Azure portal](https://docs.microsoft.com/en-us/graph/auth-register-app-v2).
|
||||
2. Under **"Authentication/Platform configurations/Web"** enter the correct url constructed as domain + `/auth/microsoft/callback`. i.e. `https://example.mysite.com/auth/microsoft/callback`
|
||||
3. In "Overview" take note of the **Application (client) ID**
|
||||
4. Choose the new project from the top right project dropdown (only if another project is selected)
|
||||
5. Select "Certificates & secrets" and click on "+ New Client Secret".
|
||||
|
||||
|
||||
#### GitHub Auth Provider
|
||||
|
||||
1. Create a new **"OAuth App"**: https://github.com/settings/developers
|
||||
@@ -361,6 +373,20 @@ _instructions for google oauth2 setup borrowed from [oauth2_proxy](https://githu
|
||||
|
||||
For more details refer to [Yandex OAuth](https://tech.yandex.com/oauth/doc/dg/concepts/about-docpage/) and [Yandex.Passport](https://tech.yandex.com/passport/doc/dg/index-docpage/) API documentation.
|
||||
|
||||
##### Battle.net Auth Provider
|
||||
|
||||
1. Log into Battle.net as a developer: https://develop.battle.net/nav/login-redirect
|
||||
1. Click "+ CREATE CLIENT" https://develop.battle.net/access/clients/create
|
||||
1. For "Client name", enter whatever you want
|
||||
1. For "Redirect URLs", one of the lines must be "http\[s\]://your_remark_installation:port//auth/battlenet/callback", e.g. https://localhost:8443/auth/battlenet/callback or https://remark.mysite.com/auth/battlenet/callback
|
||||
1. For "Service URL", enter the URL to your site or check "I do not have a service URL for this client." checkbox if you don't have any
|
||||
1. For "Intended use", describe the application you're developing
|
||||
1. Click "Save".
|
||||
1. You can see your client ID and client secret at https://develop.battle.net/access/clients by clicking the client you created
|
||||
|
||||
For more details refer to [Complete Guide of Battle.net OAuth API and Login Button](https://hakanu.net/oauth/2017/01/26/complete-guide-of-battle-net-oauth-api-and-login-button/) or [the official Battle.net OAuth2 guide](https://develop.battle.net/documentation/guides/using-oauth)
|
||||
|
||||
|
||||
#### Twitter Auth Provider
|
||||
1. Create a new twitter application https://developer.twitter.com/en/apps
|
||||
1. Fill **App name** and **Description** and **URL** of your site
|
||||
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
// Package auth provides "social login" with Github, Google, Facebook and Yandex as well as custom auth providers.
|
||||
// Package auth provides "social login" with Github, Google, Facebook, Microsoft, Yandex and Battle.net as well as custom auth providers.
|
||||
package auth
|
||||
|
||||
import (
|
||||
@@ -222,6 +222,10 @@ func (s *Service) AddProvider(name, cid, csecret string) {
|
||||
s.providers = append(s.providers, provider.NewService(provider.NewFacebook(p)))
|
||||
case "yandex":
|
||||
s.providers = append(s.providers, provider.NewService(provider.NewYandex(p)))
|
||||
case "battlenet":
|
||||
s.providers = append(s.providers, provider.NewService(provider.NewBattlenet(p)))
|
||||
case "microsoft":
|
||||
s.providers = append(s.providers, provider.NewService(provider.NewMicrosoft(p)))
|
||||
case "twitter":
|
||||
s.providers = append(s.providers, provider.NewService(provider.NewTwitter(p)))
|
||||
case "dev":
|
||||
|
||||
+25
-15
@@ -34,7 +34,7 @@ type Proxy struct {
|
||||
}
|
||||
|
||||
// Put stores retrieved avatar to avatar.Store. Gets image from user info. Returns proxied url
|
||||
func (p *Proxy) Put(u token.User) (avatarURL string, err error) {
|
||||
func (p *Proxy) Put(u token.User, client *http.Client) (avatarURL string, err error) {
|
||||
|
||||
// no picture for user, try to generate identicon avatar
|
||||
if u.Picture == "" {
|
||||
@@ -52,29 +52,18 @@ func (p *Proxy) Put(u token.User) (avatarURL string, err error) {
|
||||
return p.URL + p.RoutePath + "/" + avatarID, nil
|
||||
}
|
||||
|
||||
// load avatar from remote location
|
||||
client := http.Client{Timeout: 10 * time.Second}
|
||||
var resp *http.Response
|
||||
err = retry(5, time.Second, func() error {
|
||||
var e error
|
||||
resp, e = client.Get(u.Picture)
|
||||
return e
|
||||
})
|
||||
body, err := p.load(u.Picture, client)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to fetch avatar from the orig")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if e := resp.Body.Close(); e != nil {
|
||||
if e := body.Close(); e != nil {
|
||||
p.Logf("[WARN] can't close response body, %s", e)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", errors.Errorf("failed to get avatar from the orig, status %s", resp.Status)
|
||||
}
|
||||
|
||||
avatarID, err := p.Store.Put(u.ID, p.resize(resp.Body, p.ResizeLimit)) // put returns avatar base name, like 123456.image
|
||||
avatarID, err := p.Store.Put(u.ID, p.resize(body, p.ResizeLimit)) // put returns avatar base name, like 123456.image
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -83,6 +72,27 @@ func (p *Proxy) Put(u token.User) (avatarURL string, err error) {
|
||||
return p.URL + p.RoutePath + "/" + avatarID, nil
|
||||
}
|
||||
|
||||
// load avatar from remote url and return body. Caller has to close the reader
|
||||
func (p *Proxy) load(url string, client *http.Client) (rc io.ReadCloser, err error) {
|
||||
// load avatar from remote location
|
||||
var resp *http.Response
|
||||
err = retry(5, time.Second, func() error {
|
||||
var e error
|
||||
resp, e = client.Get(url)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch avatar from the orig")
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
_ = resp.Body.Close() // caller won't close on error
|
||||
return nil, errors.Errorf("failed to get avatar from the orig, status %s", resp.Status)
|
||||
}
|
||||
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
// Handler returns token routes for given provider
|
||||
func (p *Proxy) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,7 @@
|
||||
module github.com/go-pkgz/auth
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/dghubble/oauth1 v0.6.0
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
@@ -14,5 +16,3 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
gopkg.in/oauth2.v3 v3.12.0
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pkgz/auth/token"
|
||||
)
|
||||
|
||||
// UserUpdater defines interface adding extras or modifying UserInfo in request context
|
||||
type UserUpdater interface {
|
||||
Update(claims token.User) token.User
|
||||
}
|
||||
|
||||
// UserUpdFunc type is an adapter to allow the use of ordinary functions as UserUpdater. If f is a function
|
||||
// with the appropriate signature, UserUpdFunc(f) is a Handler that calls f.
|
||||
type UserUpdFunc func(user token.User) token.User
|
||||
|
||||
// Update calls f(user)
|
||||
func (f UserUpdFunc) Update(user token.User) token.User {
|
||||
return f(user)
|
||||
}
|
||||
|
||||
// UpdateUser update user info with UserUpdater if it exists in request's context. Otherwise do nothing.
|
||||
// should be places after either Auth, Trace or AdminOnly middleware.
|
||||
func (a *Authenticator) UpdateUser(upd UserUpdater) func(http.Handler) http.Handler {
|
||||
f := func(h http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
// call update only if user info exists, otherwise do nothing
|
||||
if user, err := token.GetUserInfo(r); err == nil {
|
||||
r = token.SetUserInfo(r, upd.Update(user))
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
return f
|
||||
}
|
||||
+2
-1
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/go-pkgz/rest"
|
||||
@@ -63,7 +64,7 @@ func (p DirectHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Name: user,
|
||||
ID: p.ProviderName + "_" + token.HashID(sha1.New(), user),
|
||||
}
|
||||
u, err = setAvatar(p.AvatarSaver, u)
|
||||
u, err = setAvatar(p.AvatarSaver, u, &http.Client{Timeout: 5 * time.Second})
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to save avatar to proxy")
|
||||
return
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ func (h Oauth1Handler) AuthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
h.Logf("[DEBUG] got raw user info %+v", jData)
|
||||
|
||||
u := h.mapUser(jData, data)
|
||||
u, err = setAvatar(h.AvatarSaver, u)
|
||||
u, err = setAvatar(h.AvatarSaver, u, &http.Client{Timeout: 5 * time.Second})
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, h.L, http.StatusInternalServerError, err, "failed to save avatar to proxy")
|
||||
return
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ func (p Oauth2Handler) AuthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
p.Logf("[DEBUG] got raw user info %+v", jData)
|
||||
|
||||
u := p.mapUser(jData, data)
|
||||
u, err = setAvatar(p.AvatarSaver, u)
|
||||
u, err = setAvatar(p.AvatarSaver, u, client)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to save avatar to proxy")
|
||||
return
|
||||
|
||||
+44
@@ -6,9 +6,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/facebook"
|
||||
"golang.org/x/oauth2/github"
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/oauth2/microsoft"
|
||||
"golang.org/x/oauth2/yandex"
|
||||
|
||||
"github.com/dghubble/oauth1"
|
||||
@@ -147,3 +149,45 @@ func NewTwitter(p Params) Oauth1Handler {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// NewBattlenet makes Battle.net oauth2 provider
|
||||
func NewBattlenet(p Params) Oauth2Handler {
|
||||
return initOauth2Handler(p, Oauth2Handler{
|
||||
name: "battlenet",
|
||||
endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://eu.battle.net/oauth/authorize",
|
||||
TokenURL: "https://eu.battle.net/oauth/token",
|
||||
AuthStyle: oauth2.AuthStyleInParams,
|
||||
},
|
||||
scopes: []string{},
|
||||
infoURL: "https://eu.battle.net/oauth/userinfo",
|
||||
mapUser: func(data UserData, _ []byte) token.User {
|
||||
userInfo := token.User{
|
||||
ID: "battlenet_" + token.HashID(sha1.New(), data.Value("id")),
|
||||
Name: data.Value("battletag"),
|
||||
}
|
||||
|
||||
return userInfo
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// NewMicrosoft makes microsoft azure oauth2 provider
|
||||
func NewMicrosoft(p Params) Oauth2Handler {
|
||||
return initOauth2Handler(p, Oauth2Handler{
|
||||
name: "microsoft",
|
||||
endpoint: microsoft.AzureADEndpoint("consumers"),
|
||||
scopes: []string{"User.Read"},
|
||||
infoURL: "https://graph.microsoft.com/v1.0/me",
|
||||
// non-beta doesn't provide photo for consumers yet
|
||||
// see https://github.com/microsoftgraph/microsoft-graph-docs/issues/3990
|
||||
mapUser: func(data UserData, b []byte) token.User {
|
||||
userInfo := token.User{
|
||||
ID: "microsoft_" + token.HashID(sha1.New(), data.Value("id")),
|
||||
Name: data.Value("displayName"),
|
||||
Picture: "https://graph.microsoft.com/beta/me/photo/$value",
|
||||
}
|
||||
return userInfo
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@ func NewService(p Provider) Service {
|
||||
|
||||
// AvatarSaver defines minimal interface to save avatar
|
||||
type AvatarSaver interface {
|
||||
Put(u token.User) (avatarURL string, err error)
|
||||
Put(u token.User, client *http.Client) (avatarURL string, err error)
|
||||
}
|
||||
|
||||
// TokenService defines interface accessing tokens
|
||||
@@ -72,9 +72,9 @@ func (p Service) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// setAvatar saves avatar and puts proxied URL to u.Picture
|
||||
func setAvatar(ava AvatarSaver, u token.User) (token.User, error) {
|
||||
func setAvatar(ava AvatarSaver, u token.User, client *http.Client) (token.User, error) {
|
||||
if ava != nil {
|
||||
avatarURL, e := ava.Put(u)
|
||||
avatarURL, e := ava.Put(u, client)
|
||||
if e != nil {
|
||||
return u, errors.Wrap(e, "failed to save avatar for")
|
||||
}
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ func (e VerifyHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if u, err = setAvatar(e.AvatarSaver, u); err != nil {
|
||||
if u, err = setAvatar(e.AvatarSaver, u, &http.Client{Timeout: 5 * time.Second}); err != nil {
|
||||
rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "failed to save avatar to proxy")
|
||||
return
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package microsoft provides constants for using OAuth2 to access Windows Live ID.
|
||||
package microsoft // import "golang.org/x/oauth2/microsoft"
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// LiveConnectEndpoint is Windows's Live ID OAuth 2.0 endpoint.
|
||||
var LiveConnectEndpoint = oauth2.Endpoint{
|
||||
AuthURL: "https://login.live.com/oauth20_authorize.srf",
|
||||
TokenURL: "https://login.live.com/oauth20_token.srf",
|
||||
}
|
||||
|
||||
// AzureADEndpoint returns a new oauth2.Endpoint for the given tenant at Azure Active Directory.
|
||||
// If tenant is empty, it uses the tenant called `common`.
|
||||
//
|
||||
// For more information see:
|
||||
// https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints
|
||||
func AzureADEndpoint(tenant string) oauth2.Endpoint {
|
||||
if tenant == "" {
|
||||
tenant = "common"
|
||||
}
|
||||
return oauth2.Endpoint{
|
||||
AuthURL: "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/authorize",
|
||||
TokenURL: "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token",
|
||||
}
|
||||
}
|
||||
Vendored
+2
-1
@@ -72,7 +72,7 @@ github.com/go-chi/cors
|
||||
# github.com/go-chi/render v1.0.1
|
||||
## explicit
|
||||
github.com/go-chi/render
|
||||
# github.com/go-pkgz/auth v0.10.2
|
||||
# github.com/go-pkgz/auth v0.11.0
|
||||
## explicit
|
||||
github.com/go-pkgz/auth
|
||||
github.com/go-pkgz/auth/avatar
|
||||
@@ -243,6 +243,7 @@ golang.org/x/oauth2/google
|
||||
golang.org/x/oauth2/internal
|
||||
golang.org/x/oauth2/jws
|
||||
golang.org/x/oauth2/jwt
|
||||
golang.org/x/oauth2/microsoft
|
||||
golang.org/x/oauth2/yandex
|
||||
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sync/semaphore
|
||||
|
||||
Reference in New Issue
Block a user