| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package server | 5 package server |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "net/http" | 9 "net/http" |
| 10 "strings" | 10 "strings" |
| 11 "time" | 11 "time" |
| 12 | 12 |
| 13 "golang.org/x/net/context" | 13 "golang.org/x/net/context" |
| 14 | 14 |
| 15 "github.com/luci/gae/service/info" | 15 "github.com/luci/gae/service/info" |
| 16 "github.com/luci/gae/service/urlfetch" | 16 "github.com/luci/gae/service/urlfetch" |
| 17 "github.com/luci/gae/service/user" | 17 "github.com/luci/gae/service/user" |
| 18 | 18 |
| 19 "github.com/luci/luci-go/common/data/caching/proccache" | 19 "github.com/luci/luci-go/common/data/caching/proccache" |
| 20 "github.com/luci/luci-go/common/errors" | 20 "github.com/luci/luci-go/common/errors" |
| 21 "github.com/luci/luci-go/common/gcloud/googleoauth" | 21 "github.com/luci/luci-go/common/gcloud/googleoauth" |
| 22 "github.com/luci/luci-go/common/logging" | 22 "github.com/luci/luci-go/common/logging" |
| 23 "github.com/luci/luci-go/common/retry" |
| 23 "github.com/luci/luci-go/server/auth" | 24 "github.com/luci/luci-go/server/auth" |
| 24 "github.com/luci/luci-go/server/auth/identity" | 25 "github.com/luci/luci-go/server/auth/identity" |
| 25 ) | 26 ) |
| 26 | 27 |
| 27 // EmailScope is a scope used to identifies user's email. Present in most tokens | 28 // EmailScope is a scope used to identifies user's email. Present in most tokens |
| 28 // by default. Can be used as a base scope for authentication. | 29 // by default. Can be used as a base scope for authentication. |
| 29 const EmailScope = "https://www.googleapis.com/auth/userinfo.email" | 30 const EmailScope = "https://www.googleapis.com/auth/userinfo.email" |
| 30 | 31 |
| 31 // OAuth2Method implements auth.Method on top of GAE OAuth2 API. It doesn't | 32 // OAuth2Method implements auth.Method on top of GAE OAuth2 API. It doesn't |
| 32 // implement auth.UsersAPI. | 33 // implement auth.UsersAPI. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 if idErr != nil { | 72 if idErr != nil { |
| 72 return nil, idErr | 73 return nil, idErr |
| 73 } | 74 } |
| 74 return &auth.User{ | 75 return &auth.User{ |
| 75 Identity: id, | 76 Identity: id, |
| 76 Superuser: u.Admin, | 77 Superuser: u.Admin, |
| 77 Email: u.Email, | 78 Email: u.Email, |
| 78 ClientID: u.ClientID, | 79 ClientID: u.ClientID, |
| 79 }, nil | 80 }, nil |
| 80 } | 81 } |
| 81 » return nil, errors.WrapTransient(err) | 82 » return nil, retry.Tag.Apply(err) |
| 82 } | 83 } |
| 83 | 84 |
| 84 type tokenCheckCache string | 85 type tokenCheckCache string |
| 85 | 86 |
| 86 // authenticateDevServer is called on dev server. It is using OAuth2 tokeninfo | 87 // authenticateDevServer is called on dev server. It is using OAuth2 tokeninfo |
| 87 // endpoint via URL fetch. It is slow as hell, but good enough for local manual | 88 // endpoint via URL fetch. It is slow as hell, but good enough for local manual |
| 88 // testing. | 89 // testing. |
| 89 func (m *OAuth2Method) authenticateDevServer(c context.Context, header string, s
copes []string) (*auth.User, error) { | 90 func (m *OAuth2Method) authenticateDevServer(c context.Context, header string, s
copes []string) (*auth.User, error) { |
| 90 chunks := strings.SplitN(header, " ", 2) | 91 chunks := strings.SplitN(header, " ", 2) |
| 91 if len(chunks) != 2 || (chunks[0] != "OAuth" && chunks[0] != "Bearer") { | 92 if len(chunks) != 2 || (chunks[0] != "OAuth" && chunks[0] != "Bearer") { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 102 logging.Infof(c, "oauth: Querying tokeninfo endpoint") | 103 logging.Infof(c, "oauth: Querying tokeninfo endpoint") |
| 103 tokenInfo, err := googleoauth.GetTokenInfo(c, googleoauth.TokenInfoParam
s{ | 104 tokenInfo, err := googleoauth.GetTokenInfo(c, googleoauth.TokenInfoParam
s{ |
| 104 AccessToken: accessToken, | 105 AccessToken: accessToken, |
| 105 Client: &http.Client{Transport: urlfetch.Get(c)}, | 106 Client: &http.Client{Transport: urlfetch.Get(c)}, |
| 106 Endpoint: m.tokenInfoEndpoint, | 107 Endpoint: m.tokenInfoEndpoint, |
| 107 }) | 108 }) |
| 108 if err != nil { | 109 if err != nil { |
| 109 if err == googleoauth.ErrBadToken { | 110 if err == googleoauth.ErrBadToken { |
| 110 return nil, err | 111 return nil, err |
| 111 } | 112 } |
| 112 » » return nil, errors.WrapTransient(fmt.Errorf("oauth: transient er
ror when validating token - %s", err)) | 113 » » return nil, errors.Annotate(err).Reason("oauth: transient error
when validating token"). |
| 114 » » » Tag(retry.Tag).Err() |
| 113 } | 115 } |
| 114 | 116 |
| 115 // Verify the token contains a validated email. | 117 // Verify the token contains a validated email. |
| 116 switch { | 118 switch { |
| 117 case tokenInfo.Email == "": | 119 case tokenInfo.Email == "": |
| 118 return nil, fmt.Errorf("oauth: token is not associated with an e
mail") | 120 return nil, fmt.Errorf("oauth: token is not associated with an e
mail") |
| 119 case !tokenInfo.EmailVerified: | 121 case !tokenInfo.EmailVerified: |
| 120 return nil, fmt.Errorf("oauth: email %s is not verified", tokenI
nfo.Email) | 122 return nil, fmt.Errorf("oauth: email %s is not verified", tokenI
nfo.Email) |
| 121 } | 123 } |
| 122 if tokenInfo.ExpiresIn <= 0 { | 124 if tokenInfo.ExpiresIn <= 0 { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 140 return nil, err | 142 return nil, err |
| 141 } | 143 } |
| 142 u := &auth.User{ | 144 u := &auth.User{ |
| 143 Identity: id, | 145 Identity: id, |
| 144 Email: tokenInfo.Email, | 146 Email: tokenInfo.Email, |
| 145 ClientID: tokenInfo.Aud, | 147 ClientID: tokenInfo.Aud, |
| 146 } | 148 } |
| 147 proccache.Put(c, tokenCheckCache(accessToken), u, time.Duration(tokenInf
o.ExpiresIn)*time.Second) | 149 proccache.Put(c, tokenCheckCache(accessToken), u, time.Duration(tokenInf
o.ExpiresIn)*time.Second) |
| 148 return u, nil | 150 return u, nil |
| 149 } | 151 } |
| OLD | NEW |