git.iko.soy/typeable/oauth2-proxy
on master help sign in
Add comments to exported methods for providers package
e200bd5Joel Speed
providers/azure.go+4
@@ -11,11 +11,13 @@ import (
11 "github.com/pusher/oauth2_proxy/api"
11 "github.com/pusher/oauth2_proxy/api"
12)
12)
13
13
14+// AzureProvider represents an Azure based Identity Provider
14type AzureProvider struct {
15type AzureProvider struct {
15 *ProviderData
16 *ProviderData
16 Tenant string
17 Tenant string
17}
18}
18
19
20+// NewAzureProvider initiates a new AzureProvider
19func NewAzureProvider(p *ProviderData) *AzureProvider {
21func NewAzureProvider(p *ProviderData) *AzureProvider {
20 p.ProviderName = "Azure"
22 p.ProviderName = "Azure"
21
23
@@ -40,6 +42,7 @@ func NewAzureProvider(p *ProviderData) *AzureProvider {
40 return &AzureProvider{ProviderData: p}
42 return &AzureProvider{ProviderData: p}
41}
43}
42
44
45+// Configure defaults the AzureProvider configuration options
43func (p *AzureProvider) Configure(tenant string) {
46func (p *AzureProvider) Configure(tenant string) {
44 p.Tenant = tenant
47 p.Tenant = tenant
45 if tenant == "" {
48 if tenant == "" {
@@ -84,6 +87,7 @@ func getEmailFromJSON(json *simplejson.Json) (string, error) {
84 return email, err
87 return email, err
85}
88}
86
89
90+// GetEmailAddress returns the Account email address
87func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
91func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
88 var email string
92 var email string
89 var err error
93 var err error
providers/facebook.go+4
@@ -9,10 +9,12 @@ import (
9 "github.com/pusher/oauth2_proxy/api"
9 "github.com/pusher/oauth2_proxy/api"
10)
10)
11
11
12+// FacebookProvider represents an Facebook based Identity Provider
12type FacebookProvider struct {
13type FacebookProvider struct {
13 *ProviderData
14 *ProviderData
14}
15}
15
16
17+// NewFacebookProvider initiates a new FacebookProvider
16func NewFacebookProvider(p *ProviderData) *FacebookProvider {
18func NewFacebookProvider(p *ProviderData) *FacebookProvider {
17 p.ProviderName = "Facebook"
19 p.ProviderName = "Facebook"
18 if p.LoginURL.String() == "" {
20 if p.LoginURL.String() == "" {
@@ -51,6 +53,7 @@ func getFacebookHeader(accessToken string) http.Header {
51 return header
53 return header
52}
54}
53
55
56+// GetEmailAddress returns the Account email address
54func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) {
57func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) {
55 if s.AccessToken == "" {
58 if s.AccessToken == "" {
56 return "", errors.New("missing access token")
59 return "", errors.New("missing access token")
@@ -75,6 +78,7 @@ func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) {
75 return r.Email, nil
78 return r.Email, nil
76}
79}
77
80
81+// ValidateSessionState validates the AccessToken
78func (p *FacebookProvider) ValidateSessionState(s *SessionState) bool {
82func (p *FacebookProvider) ValidateSessionState(s *SessionState) bool {
79 return validateToken(p, s.AccessToken, getFacebookHeader(s.AccessToken))
83 return validateToken(p, s.AccessToken, getFacebookHeader(s.AccessToken))
80}
84}
providers/github.go+6
@@ -12,12 +12,14 @@ import (
12 "strings"
12 "strings"
13)
13)
14
14
15+// GitHubProvider represents an GitHub based Identity Provider
15type GitHubProvider struct {
16type GitHubProvider struct {
16 *ProviderData
17 *ProviderData
17 Org string
18 Org string
18 Team string
19 Team string
19}
20}
20
21
22+// NewGitHubProvider initiates a new GitHubProvider
21func NewGitHubProvider(p *ProviderData) *GitHubProvider {
23func NewGitHubProvider(p *ProviderData) *GitHubProvider {
22 p.ProviderName = "GitHub"
24 p.ProviderName = "GitHub"
23 if p.LoginURL == nil || p.LoginURL.String() == "" {
25 if p.LoginURL == nil || p.LoginURL.String() == "" {
@@ -47,6 +49,8 @@ func NewGitHubProvider(p *ProviderData) *GitHubProvider {
47 }
49 }
48 return &GitHubProvider{ProviderData: p}
50 return &GitHubProvider{ProviderData: p}
49}
51}
52+
53+// SetOrgTeam adds GitHub org reading parameters to the OAuth2 scope
50func (p *GitHubProvider) SetOrgTeam(org, team string) {
54func (p *GitHubProvider) SetOrgTeam(org, team string) {
51 p.Org = org
55 p.Org = org
52 p.Team = team
56 p.Team = team
@@ -194,6 +198,7 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
194 return false, nil
198 return false, nil
195}
199}
196
200
201+// GetEmailAddress returns the Account email address
197func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) {
202func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) {
198
203
199 var emails []struct {
204 var emails []struct {
@@ -251,6 +256,7 @@ func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) {
251 return "", nil
256 return "", nil
252}
257}
253
258
259+// GetUserName returns the Account user name
254func (p *GitHubProvider) GetUserName(s *SessionState) (string, error) {
260func (p *GitHubProvider) GetUserName(s *SessionState) (string, error) {
255 var user struct {
261 var user struct {
256 Login string `json:"login"`
262 Login string `json:"login"`
providers/gitlab.go+3
@@ -8,10 +8,12 @@ import (
8 "github.com/pusher/oauth2_proxy/api"
8 "github.com/pusher/oauth2_proxy/api"
9)
9)
10
10
11+// GitLabProvider represents an GitLab based Identity Provider
11type GitLabProvider struct {
12type GitLabProvider struct {
12 *ProviderData
13 *ProviderData
13}
14}
14
15
16+// NewGitLabProvider initiates a new GitLabProvider
15func NewGitLabProvider(p *ProviderData) *GitLabProvider {
17func NewGitLabProvider(p *ProviderData) *GitLabProvider {
16 p.ProviderName = "GitLab"
18 p.ProviderName = "GitLab"
17 if p.LoginURL == nil || p.LoginURL.String() == "" {
19 if p.LoginURL == nil || p.LoginURL.String() == "" {
@@ -41,6 +43,7 @@ func NewGitLabProvider(p *ProviderData) *GitLabProvider {
41 return &GitLabProvider{ProviderData: p}
43 return &GitLabProvider{ProviderData: p}
42}
44}
43
45
46+// GetEmailAddress returns the Account email address
44func (p *GitLabProvider) GetEmailAddress(s *SessionState) (string, error) {
47func (p *GitLabProvider) GetEmailAddress(s *SessionState) (string, error) {
45
48
46 req, err := http.NewRequest("GET",
49 req, err := http.NewRequest("GET",
providers/google.go+5
@@ -20,6 +20,7 @@ import (
20 "google.golang.org/api/googleapi"
20 "google.golang.org/api/googleapi"
21)
21)
22
22
23+// GoogleProvider represents an Google based Identity Provider
23type GoogleProvider struct {
24type GoogleProvider struct {
24 *ProviderData
25 *ProviderData
25 RedeemRefreshURL *url.URL
26 RedeemRefreshURL *url.URL
@@ -28,6 +29,7 @@ type GoogleProvider struct {
28 GroupValidator func(string) bool
29 GroupValidator func(string) bool
29}
30}
30
31
32+// NewGoogleProvider initiates a new GoogleProvider
31func NewGoogleProvider(p *ProviderData) *GoogleProvider {
33func NewGoogleProvider(p *ProviderData) *GoogleProvider {
32 p.ProviderName = "Google"
34 p.ProviderName = "Google"
33 if p.LoginURL.String() == "" {
35 if p.LoginURL.String() == "" {
@@ -90,6 +92,7 @@ func emailFromIDToken(idToken string) (string, error) {
90 return email.Email, nil
92 return email.Email, nil
91}
93}
92
94
95+// Redeem exchanges the OAuth2 authentication token for an ID token
93func (p *GoogleProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
96func (p *GoogleProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
94 if code == "" {
97 if code == "" {
95 err = errors.New("missing code")
98 err = errors.New("missing code")
@@ -249,6 +252,8 @@ func (p *GoogleProvider) ValidateGroup(email string) bool {
249 return p.GroupValidator(email)
252 return p.GroupValidator(email)
250}
253}
251
254
255+// RefreshSessionIfNeeded checks if the session has expired and uses the
256+// RefreshToken to fetch a new ID token if required
252func (p *GoogleProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
257func (p *GoogleProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
253 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
258 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
254 return false, nil
259 return false, nil
providers/linkedin.go+4
@@ -9,10 +9,12 @@ import (
9 "github.com/pusher/oauth2_proxy/api"
9 "github.com/pusher/oauth2_proxy/api"
10)
10)
11
11
12+// LinkedInProvider represents an LinkedIn based Identity Provider
12type LinkedInProvider struct {
13type LinkedInProvider struct {
13 *ProviderData
14 *ProviderData
14}
15}
15
16
17+// NewLinkedInProvider initiates a new LinkedInProvider
16func NewLinkedInProvider(p *ProviderData) *LinkedInProvider {
18func NewLinkedInProvider(p *ProviderData) *LinkedInProvider {
17 p.ProviderName = "LinkedIn"
19 p.ProviderName = "LinkedIn"
18 if p.LoginURL.String() == "" {
20 if p.LoginURL.String() == "" {
@@ -47,6 +49,7 @@ func getLinkedInHeader(accessToken string) http.Header {
47 return header
49 return header
48}
50}
49
51
52+// GetEmailAddress returns the Account email address
50func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) {
53func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) {
51 if s.AccessToken == "" {
54 if s.AccessToken == "" {
52 return "", errors.New("missing access token")
55 return "", errors.New("missing access token")
@@ -69,6 +72,7 @@ func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) {
69 return email, nil
72 return email, nil
70}
73}
71
74
75+// ValidateSessionState validates the AccessToken
72func (p *LinkedInProvider) ValidateSessionState(s *SessionState) bool {
76func (p *LinkedInProvider) ValidateSessionState(s *SessionState) bool {
73 return validateToken(p, s.AccessToken, getLinkedInHeader(s.AccessToken))
77 return validateToken(p, s.AccessToken, getLinkedInHeader(s.AccessToken))
74}
78}
providers/oidc.go+8
@@ -10,17 +10,20 @@ import (
10 oidc "github.com/coreos/go-oidc"
10 oidc "github.com/coreos/go-oidc"
11)
11)
12
12
13+// OIDCProvider represents an OIDC based Identity Provider
13type OIDCProvider struct {
14type OIDCProvider struct {
14 *ProviderData
15 *ProviderData
15
16
16 Verifier *oidc.IDTokenVerifier
17 Verifier *oidc.IDTokenVerifier
17}
18}
18
19
20+// NewOIDCProvider initiates a new OIDCProvider
19func NewOIDCProvider(p *ProviderData) *OIDCProvider {
21func NewOIDCProvider(p *ProviderData) *OIDCProvider {
20 p.ProviderName = "OpenID Connect"
22 p.ProviderName = "OpenID Connect"
21 return &OIDCProvider{ProviderData: p}
23 return &OIDCProvider{ProviderData: p}
22}
24}
23
25
26+// Redeem exchanges the OAuth2 authentication token for an ID token
24func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
27func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
25 ctx := context.Background()
28 ctx := context.Background()
26 c := oauth2.Config{
29 c := oauth2.Config{
@@ -73,6 +76,11 @@ func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err er
73 return
76 return
74}
77}
75
78
79+// RefreshSessionIfNeeded checks if the session has expired and uses the
80+// RefreshToken to fetch a new ID token if required
81+//
82+// WARNGING: This implementation is broken and does not check with the upstream
83+// OIDC provider before refreshing the session
76func (p *OIDCProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
84func (p *OIDCProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
77 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
85 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
78 return false, nil
86 return false, nil
providers/provider_data.go+3
@@ -4,6 +4,8 @@ import (
4 "net/url"
4 "net/url"
5)
5)
6
6
7+// ProviderData contains information required to configure all implementations
8+// of OAuth2 providers
7type ProviderData struct {
9type ProviderData struct {
8 ProviderName string
10 ProviderName string
9 ClientID string
11 ClientID string
@@ -17,4 +19,5 @@ type ProviderData struct {
17 ApprovalPrompt string
19 ApprovalPrompt string
18}
20}
19
21
22+// Data returns the ProviderData
20func (p *ProviderData) Data() *ProviderData { return p }
23func (p *ProviderData) Data() *ProviderData { return p }
providers/provider_default.go+3
@@ -12,6 +12,7 @@ import (
12 "github.com/pusher/oauth2_proxy/cookie"
12 "github.com/pusher/oauth2_proxy/cookie"
13)
13)
14
14
15+// Redeem provides a default implementation of the OAuth2 token redemption process
15func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err error) {
16func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err error) {
16 if code == "" {
17 if code == "" {
17 err = errors.New("missing code")
18 err = errors.New("missing code")
@@ -102,6 +103,7 @@ func (p *ProviderData) SessionFromCookie(v string, c *cookie.Cipher) (s *Session
102 return DecodeSessionState(v, c)
103 return DecodeSessionState(v, c)
103}
104}
104
105
106+// GetEmailAddress returns the Account email address
105func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) {
107func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) {
106 return "", errors.New("not implemented")
108 return "", errors.New("not implemented")
107}
109}
@@ -117,6 +119,7 @@ func (p *ProviderData) ValidateGroup(email string) bool {
117 return true
119 return true
118}
120}
119
121
122+// ValidateSessionState validates the AccessToken
120func (p *ProviderData) ValidateSessionState(s *SessionState) bool {
123func (p *ProviderData) ValidateSessionState(s *SessionState) bool {
121 return validateToken(p, s.AccessToken, nil)
124 return validateToken(p, s.AccessToken, nil)
122}
125}
providers/providers.go+2
@@ -4,6 +4,7 @@ import (
4 "github.com/pusher/oauth2_proxy/cookie"
4 "github.com/pusher/oauth2_proxy/cookie"
5)
5)
6
6
7+// Provider represents an upstream identity provider implementation
7type Provider interface {
8type Provider interface {
8 Data() *ProviderData
9 Data() *ProviderData
9 GetEmailAddress(*SessionState) (string, error)
10 GetEmailAddress(*SessionState) (string, error)
@@ -17,6 +18,7 @@ type Provider interface {
17 CookieForSession(*SessionState, *cookie.Cipher) (string, error)
18 CookieForSession(*SessionState, *cookie.Cipher) (string, error)
18}
19}
19
20
21+// New provides a new Provider based on the configured provider string
20func New(provider string, p *ProviderData) Provider {
22func New(provider string, p *ProviderData) Provider {
21 switch provider {
23 switch provider {
22 case "linkedin":
24 case "linkedin":
providers/session_state.go+6
@@ -9,6 +9,7 @@ import (
9 "github.com/pusher/oauth2_proxy/cookie"
9 "github.com/pusher/oauth2_proxy/cookie"
10)
10)
11
11
12+// SessionState is used to store information about the currently authenticated user session
12type SessionState struct {
13type SessionState struct {
13 AccessToken string
14 AccessToken string
14 ExpiresOn time.Time
15 ExpiresOn time.Time
@@ -17,6 +18,7 @@ type SessionState struct {
17 User string
18 User string
18}
19}
19
20
21+// IsExpired checks whether the session has expired
20func (s *SessionState) IsExpired() bool {
22func (s *SessionState) IsExpired() bool {
21 if !s.ExpiresOn.IsZero() && s.ExpiresOn.Before(time.Now()) {
23 if !s.ExpiresOn.IsZero() && s.ExpiresOn.Before(time.Now()) {
22 return true
24 return true
@@ -24,6 +26,7 @@ func (s *SessionState) IsExpired() bool {
24 return false
26 return false
25}
27}
26
28
29+// String constructs a summary of the session state
27func (s *SessionState) String() string {
30func (s *SessionState) String() string {
28 o := fmt.Sprintf("Session{%s", s.accountInfo())
31 o := fmt.Sprintf("Session{%s", s.accountInfo())
29 if s.AccessToken != "" {
32 if s.AccessToken != "" {
@@ -38,6 +41,7 @@ func (s *SessionState) String() string {
38 return o + "}"
41 return o + "}"
39}
42}
40
43
44+// EncodeSessionState returns string representation of the current session
41func (s *SessionState) EncodeSessionState(c *cookie.Cipher) (string, error) {
45func (s *SessionState) EncodeSessionState(c *cookie.Cipher) (string, error) {
42 if c == nil || s.AccessToken == "" {
46 if c == nil || s.AccessToken == "" {
43 return s.accountInfo(), nil
47 return s.accountInfo(), nil
@@ -49,6 +53,7 @@ func (s *SessionState) accountInfo() string {
49 return fmt.Sprintf("email:%s user:%s", s.Email, s.User)
53 return fmt.Sprintf("email:%s user:%s", s.Email, s.User)
50}
54}
51
55
56+// EncryptedString encrypts the session state into a cookie string
52func (s *SessionState) EncryptedString(c *cookie.Cipher) (string, error) {
57func (s *SessionState) EncryptedString(c *cookie.Cipher) (string, error) {
53 var err error
58 var err error
54 if c == nil {
59 if c == nil {
@@ -84,6 +89,7 @@ func decodeSessionStatePlain(v string) (s *SessionState, err error) {
84 return &SessionState{User: user, Email: email}, nil
89 return &SessionState{User: user, Email: email}, nil
85}
90}
86
91
92+// DecodeSessionState decodes the session cookie string into a SessionState
87func DecodeSessionState(v string, c *cookie.Cipher) (s *SessionState, err error) {
93func DecodeSessionState(v string, c *cookie.Cipher) (s *SessionState, err error) {
88 if c == nil {
94 if c == nil {
89 return decodeSessionStatePlain(v)
95 return decodeSessionStatePlain(v)