git.iko.soy/typeable/oauth2-proxy
on master help sign in
Move SessionState to its own package
2ab8a7dJoel Speed
oauthproxy.go+7−6
@@ -16,6 +16,7 @@ import (
16 "github.com/mbland/hmacauth"
16 "github.com/mbland/hmacauth"
17 "github.com/pusher/oauth2_proxy/cookie"
17 "github.com/pusher/oauth2_proxy/cookie"
18 "github.com/pusher/oauth2_proxy/logger"
18 "github.com/pusher/oauth2_proxy/logger"
19+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
19 "github.com/pusher/oauth2_proxy/providers"
20 "github.com/pusher/oauth2_proxy/providers"
20 "github.com/yhat/wsutil"
21 "github.com/yhat/wsutil"
21)
22)
@@ -292,7 +293,7 @@ func (p *OAuthProxy) displayCustomLoginForm() bool {
292 return p.HtpasswdFile != nil && p.DisplayHtpasswdForm
293 return p.HtpasswdFile != nil && p.DisplayHtpasswdForm
293}
294}
294
295
295−func (p *OAuthProxy) redeemCode(host, code string) (s *providers.SessionState, err error) {
296+func (p *OAuthProxy) redeemCode(host, code string) (s *sessions.SessionState, err error) {
296 if code == "" {
297 if code == "" {
297 return nil, errors.New("missing code")
298 return nil, errors.New("missing code")
298 }
299 }
@@ -484,7 +485,7 @@ func (p *OAuthProxy) SetSessionCookie(rw http.ResponseWriter, req *http.Request,
484}
485}
485
486
486// LoadCookiedSession reads the user's authentication details from the request
487// LoadCookiedSession reads the user's authentication details from the request
487−func (p *OAuthProxy) LoadCookiedSession(req *http.Request) (*providers.SessionState, time.Duration, error) {
488+func (p *OAuthProxy) LoadCookiedSession(req *http.Request) (*sessions.SessionState, time.Duration, error) {
488 var age time.Duration
489 var age time.Duration
489 c, err := loadCookie(req, p.CookieName)
490 c, err := loadCookie(req, p.CookieName)
490 if err != nil {
491 if err != nil {
@@ -506,7 +507,7 @@ func (p *OAuthProxy) LoadCookiedSession(req *http.Request) (*providers.SessionSt
506}
507}
507
508
508// SaveSession creates a new session cookie value and sets this on the response
509// SaveSession creates a new session cookie value and sets this on the response
509−func (p *OAuthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *providers.SessionState) error {
510+func (p *OAuthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *sessions.SessionState) error {
510 value, err := p.provider.CookieForSession(s, p.CookieCipher)
511 value, err := p.provider.CookieForSession(s, p.CookieCipher)
511 if err != nil {
512 if err != nil {
512 return err
513 return err
@@ -693,7 +694,7 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) {
693
694
694 user, ok := p.ManualSignIn(rw, req)
695 user, ok := p.ManualSignIn(rw, req)
695 if ok {
696 if ok {
696− session := &providers.SessionState{User: user}
697+ session := &sessions.SessionState{User: user}
697 p.SaveSession(rw, req, session)
698 p.SaveSession(rw, req, session)
698 http.Redirect(rw, req, redirect, 302)
699 http.Redirect(rw, req, redirect, 302)
699 } else {
700 } else {
@@ -944,7 +945,7 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int
944
945
945// CheckBasicAuth checks the requests Authorization header for basic auth
946// CheckBasicAuth checks the requests Authorization header for basic auth
946// credentials and authenticates these against the proxies HtpasswdFile
947// credentials and authenticates these against the proxies HtpasswdFile
947−func (p *OAuthProxy) CheckBasicAuth(req *http.Request) (*providers.SessionState, error) {
948+func (p *OAuthProxy) CheckBasicAuth(req *http.Request) (*sessions.SessionState, error) {
948 if p.HtpasswdFile == nil {
949 if p.HtpasswdFile == nil {
949 return nil, nil
950 return nil, nil
950 }
951 }
@@ -966,7 +967,7 @@ func (p *OAuthProxy) CheckBasicAuth(req *http.Request) (*providers.SessionState,
966 }
967 }
967 if p.HtpasswdFile.Validate(pair[0], pair[1]) {
968 if p.HtpasswdFile.Validate(pair[0], pair[1]) {
968 logger.PrintAuthf(pair[0], req, logger.AuthSuccess, "Authenticated via basic auth and HTpasswd File")
969 logger.PrintAuthf(pair[0], req, logger.AuthSuccess, "Authenticated via basic auth and HTpasswd File")
969− return &providers.SessionState{User: pair[0]}, nil
970+ return &sessions.SessionState{User: pair[0]}, nil
970 }
971 }
971 logger.PrintAuthf(pair[0], req, logger.AuthFailure, "Invalid authentication via basic auth: not in Htpasswd File")
972 logger.PrintAuthf(pair[0], req, logger.AuthFailure, "Invalid authentication via basic auth: not in Htpasswd File")
972 return nil, nil
973 return nil, nil
oauthproxy_test.go+14−13
@@ -16,6 +16,7 @@ import (
16
16
17 "github.com/mbland/hmacauth"
17 "github.com/mbland/hmacauth"
18 "github.com/pusher/oauth2_proxy/logger"
18 "github.com/pusher/oauth2_proxy/logger"
19+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
19 "github.com/pusher/oauth2_proxy/providers"
20 "github.com/pusher/oauth2_proxy/providers"
20 "github.com/stretchr/testify/assert"
21 "github.com/stretchr/testify/assert"
21 "github.com/stretchr/testify/require"
22 "github.com/stretchr/testify/require"
@@ -253,11 +254,11 @@ func NewTestProvider(providerURL *url.URL, emailAddress string) *TestProvider {
253 }
254 }
254}
255}
255
256
256−func (tp *TestProvider) GetEmailAddress(session *providers.SessionState) (string, error) {
257+func (tp *TestProvider) GetEmailAddress(session *sessions.SessionState) (string, error) {
257 return tp.EmailAddress, nil
258 return tp.EmailAddress, nil
258}
259}
259
260
260−func (tp *TestProvider) ValidateSessionState(session *providers.SessionState) bool {
261+func (tp *TestProvider) ValidateSessionState(session *sessions.SessionState) bool {
261 return tp.ValidToken
262 return tp.ValidToken
262}
263}
263
264
@@ -637,7 +638,7 @@ func (p *ProcessCookieTest) MakeCookie(value string, ref time.Time) []*http.Cook
637 return p.proxy.MakeSessionCookie(p.req, value, p.opts.CookieExpire, ref)
638 return p.proxy.MakeSessionCookie(p.req, value, p.opts.CookieExpire, ref)
638}
639}
639
640
640−func (p *ProcessCookieTest) SaveSession(s *providers.SessionState, ref time.Time) error {
641+func (p *ProcessCookieTest) SaveSession(s *sessions.SessionState, ref time.Time) error {
641 value, err := p.proxy.provider.CookieForSession(s, p.proxy.CookieCipher)
642 value, err := p.proxy.provider.CookieForSession(s, p.proxy.CookieCipher)
642 if err != nil {
643 if err != nil {
643 return err
644 return err
@@ -648,14 +649,14 @@ func (p *ProcessCookieTest) SaveSession(s *providers.SessionState, ref time.Time
648 return nil
649 return nil
649}
650}
650
651
651−func (p *ProcessCookieTest) LoadCookiedSession() (*providers.SessionState, time.Duration, error) {
652+func (p *ProcessCookieTest) LoadCookiedSession() (*sessions.SessionState, time.Duration, error) {
652 return p.proxy.LoadCookiedSession(p.req)
653 return p.proxy.LoadCookiedSession(p.req)
653}
654}
654
655
655func TestLoadCookiedSession(t *testing.T) {
656func TestLoadCookiedSession(t *testing.T) {
656 pcTest := NewProcessCookieTestWithDefaults()
657 pcTest := NewProcessCookieTestWithDefaults()
657
658
658− startSession := &providers.SessionState{Email: "john.doe@example.com", AccessToken: "my_access_token"}
659+ startSession := &sessions.SessionState{Email: "john.doe@example.com", AccessToken: "my_access_token"}
659 pcTest.SaveSession(startSession, time.Now())
660 pcTest.SaveSession(startSession, time.Now())
660
661
661 session, _, err := pcTest.LoadCookiedSession()
662 session, _, err := pcTest.LoadCookiedSession()
@@ -680,7 +681,7 @@ func TestProcessCookieRefreshNotSet(t *testing.T) {
680 pcTest.proxy.CookieExpire = time.Duration(23) * time.Hour
681 pcTest.proxy.CookieExpire = time.Duration(23) * time.Hour
681 reference := time.Now().Add(time.Duration(-2) * time.Hour)
682 reference := time.Now().Add(time.Duration(-2) * time.Hour)
682
683
683− startSession := &providers.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
684+ startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
684 pcTest.SaveSession(startSession, reference)
685 pcTest.SaveSession(startSession, reference)
685
686
686 session, age, err := pcTest.LoadCookiedSession()
687 session, age, err := pcTest.LoadCookiedSession()
@@ -695,7 +696,7 @@ func TestProcessCookieFailIfCookieExpired(t *testing.T) {
695 pcTest := NewProcessCookieTestWithDefaults()
696 pcTest := NewProcessCookieTestWithDefaults()
696 pcTest.proxy.CookieExpire = time.Duration(24) * time.Hour
697 pcTest.proxy.CookieExpire = time.Duration(24) * time.Hour
697 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
698 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
698− startSession := &providers.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
699+ startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
699 pcTest.SaveSession(startSession, reference)
700 pcTest.SaveSession(startSession, reference)
700
701
701 session, _, err := pcTest.LoadCookiedSession()
702 session, _, err := pcTest.LoadCookiedSession()
@@ -709,7 +710,7 @@ func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
709 pcTest := NewProcessCookieTestWithDefaults()
710 pcTest := NewProcessCookieTestWithDefaults()
710 pcTest.proxy.CookieExpire = time.Duration(24) * time.Hour
711 pcTest.proxy.CookieExpire = time.Duration(24) * time.Hour
711 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
712 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
712− startSession := &providers.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
713+ startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
713 pcTest.SaveSession(startSession, reference)
714 pcTest.SaveSession(startSession, reference)
714
715
715 pcTest.proxy.CookieRefresh = time.Hour
716 pcTest.proxy.CookieRefresh = time.Hour
@@ -729,7 +730,7 @@ func NewAuthOnlyEndpointTest() *ProcessCookieTest {
729
730
730func TestAuthOnlyEndpointAccepted(t *testing.T) {
731func TestAuthOnlyEndpointAccepted(t *testing.T) {
731 test := NewAuthOnlyEndpointTest()
732 test := NewAuthOnlyEndpointTest()
732− startSession := &providers.SessionState{
733+ startSession := &sessions.SessionState{
733 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
734 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
734 test.SaveSession(startSession, time.Now())
735 test.SaveSession(startSession, time.Now())
735
736
@@ -752,7 +753,7 @@ func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
752 test := NewAuthOnlyEndpointTest()
753 test := NewAuthOnlyEndpointTest()
753 test.proxy.CookieExpire = time.Duration(24) * time.Hour
754 test.proxy.CookieExpire = time.Duration(24) * time.Hour
754 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
755 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
755− startSession := &providers.SessionState{
756+ startSession := &sessions.SessionState{
756 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
757 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
757 test.SaveSession(startSession, reference)
758 test.SaveSession(startSession, reference)
758
759
@@ -764,7 +765,7 @@ func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
764
765
765func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) {
766func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) {
766 test := NewAuthOnlyEndpointTest()
767 test := NewAuthOnlyEndpointTest()
767− startSession := &providers.SessionState{
768+ startSession := &sessions.SessionState{
768 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
769 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token"}
769 test.SaveSession(startSession, time.Now())
770 test.SaveSession(startSession, time.Now())
770 test.validateUser = false
771 test.validateUser = false
@@ -795,7 +796,7 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
795 pcTest.req, _ = http.NewRequest("GET",
796 pcTest.req, _ = http.NewRequest("GET",
796 pcTest.opts.ProxyPrefix+"/auth", nil)
797 pcTest.opts.ProxyPrefix+"/auth", nil)
797
798
798− startSession := &providers.SessionState{
799+ startSession := &sessions.SessionState{
799 User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token"}
800 User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token"}
800 pcTest.SaveSession(startSession, time.Now())
801 pcTest.SaveSession(startSession, time.Now())
801
802
@@ -927,7 +928,7 @@ func (st *SignatureTest) MakeRequestWithExpectedKey(method, body, key string) {
927 req := httptest.NewRequest(method, "/foo/bar", bodyBuf)
928 req := httptest.NewRequest(method, "/foo/bar", bodyBuf)
928 req.Header = st.header
929 req.Header = st.header
929
930
930− state := &providers.SessionState{
931+ state := &sessions.SessionState{
931 Email: "mbland@acm.org", AccessToken: "my_access_token"}
932 Email: "mbland@acm.org", AccessToken: "my_access_token"}
932 value, err := proxy.provider.CookieForSession(state, proxy.CookieCipher)
933 value, err := proxy.provider.CookieForSession(state, proxy.CookieCipher)
933 if err != nil {
934 if err != nil {
providers/session_state.go → pkg/apis/sessions/session_state.gorenamed+1−1
@@ -1,4 +1,4 @@
1−package providers
1+package sessions
2
2
3import (
3import (
4 "encoding/json"
4 "encoding/json"
providers/session_state_test.go → pkg/apis/sessions/session_state_test.gorenamed+31−30
@@ -1,4 +1,4 @@
1−package providers
1+package sessions_test
2
2
3import (
3import (
4 "fmt"
4 "fmt"
@@ -6,6 +6,7 @@ import (
6 "time"
6 "time"
7
7
8 "github.com/pusher/oauth2_proxy/cookie"
8 "github.com/pusher/oauth2_proxy/cookie"
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/assert"
10)
11)
11
12
@@ -17,7 +18,7 @@ func TestSessionStateSerialization(t *testing.T) {
17 assert.Equal(t, nil, err)
18 assert.Equal(t, nil, err)
18 c2, err := cookie.NewCipher([]byte(altSecret))
19 c2, err := cookie.NewCipher([]byte(altSecret))
19 assert.Equal(t, nil, err)
20 assert.Equal(t, nil, err)
20− s := &SessionState{
21+ s := &sessions.SessionState{
21 Email: "user@domain.com",
22 Email: "user@domain.com",
22 AccessToken: "token1234",
23 AccessToken: "token1234",
23 IDToken: "rawtoken1234",
24 IDToken: "rawtoken1234",
@@ -27,7 +28,7 @@ func TestSessionStateSerialization(t *testing.T) {
27 encoded, err := s.EncodeSessionState(c)
28 encoded, err := s.EncodeSessionState(c)
28 assert.Equal(t, nil, err)
29 assert.Equal(t, nil, err)
29
30
30− ss, err := DecodeSessionState(encoded, c)
31+ ss, err := sessions.DecodeSessionState(encoded, c)
31 t.Logf("%#v", ss)
32 t.Logf("%#v", ss)
32 assert.Equal(t, nil, err)
33 assert.Equal(t, nil, err)
33 assert.Equal(t, "user@domain.com", ss.User)
34 assert.Equal(t, "user@domain.com", ss.User)
@@ -38,7 +39,7 @@ func TestSessionStateSerialization(t *testing.T) {
38 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
39 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
39
40
40 // ensure a different cipher can't decode properly (ie: it gets gibberish)
41 // ensure a different cipher can't decode properly (ie: it gets gibberish)
41− ss, err = DecodeSessionState(encoded, c2)
42+ ss, err = sessions.DecodeSessionState(encoded, c2)
42 t.Logf("%#v", ss)
43 t.Logf("%#v", ss)
43 assert.Equal(t, nil, err)
44 assert.Equal(t, nil, err)
44 assert.NotEqual(t, "user@domain.com", ss.User)
45 assert.NotEqual(t, "user@domain.com", ss.User)
@@ -54,7 +55,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
54 assert.Equal(t, nil, err)
55 assert.Equal(t, nil, err)
55 c2, err := cookie.NewCipher([]byte(altSecret))
56 c2, err := cookie.NewCipher([]byte(altSecret))
56 assert.Equal(t, nil, err)
57 assert.Equal(t, nil, err)
57− s := &SessionState{
58+ s := &sessions.SessionState{
58 User: "just-user",
59 User: "just-user",
59 Email: "user@domain.com",
60 Email: "user@domain.com",
60 AccessToken: "token1234",
61 AccessToken: "token1234",
@@ -64,7 +65,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
64 encoded, err := s.EncodeSessionState(c)
65 encoded, err := s.EncodeSessionState(c)
65 assert.Equal(t, nil, err)
66 assert.Equal(t, nil, err)
66
67
67− ss, err := DecodeSessionState(encoded, c)
68+ ss, err := sessions.DecodeSessionState(encoded, c)
68 t.Logf("%#v", ss)
69 t.Logf("%#v", ss)
69 assert.Equal(t, nil, err)
70 assert.Equal(t, nil, err)
70 assert.Equal(t, s.User, ss.User)
71 assert.Equal(t, s.User, ss.User)
@@ -74,7 +75,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
74 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
75 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
75
76
76 // ensure a different cipher can't decode properly (ie: it gets gibberish)
77 // ensure a different cipher can't decode properly (ie: it gets gibberish)
77− ss, err = DecodeSessionState(encoded, c2)
78+ ss, err = sessions.DecodeSessionState(encoded, c2)
78 t.Logf("%#v", ss)
79 t.Logf("%#v", ss)
79 assert.Equal(t, nil, err)
80 assert.Equal(t, nil, err)
80 assert.NotEqual(t, s.User, ss.User)
81 assert.NotEqual(t, s.User, ss.User)
@@ -85,7 +86,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
85}
86}
86
87
87func TestSessionStateSerializationNoCipher(t *testing.T) {
88func TestSessionStateSerializationNoCipher(t *testing.T) {
88− s := &SessionState{
89+ s := &sessions.SessionState{
89 Email: "user@domain.com",
90 Email: "user@domain.com",
90 AccessToken: "token1234",
91 AccessToken: "token1234",
91 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
92 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
@@ -95,7 +96,7 @@ func TestSessionStateSerializationNoCipher(t *testing.T) {
95 assert.Equal(t, nil, err)
96 assert.Equal(t, nil, err)
96
97
97 // only email should have been serialized
98 // only email should have been serialized
98− ss, err := DecodeSessionState(encoded, nil)
99+ ss, err := sessions.DecodeSessionState(encoded, nil)
99 assert.Equal(t, nil, err)
100 assert.Equal(t, nil, err)
100 assert.Equal(t, "user@domain.com", ss.User)
101 assert.Equal(t, "user@domain.com", ss.User)
101 assert.Equal(t, s.Email, ss.Email)
102 assert.Equal(t, s.Email, ss.Email)
@@ -104,7 +105,7 @@ func TestSessionStateSerializationNoCipher(t *testing.T) {
104}
105}
105
106
106func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
107func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
107− s := &SessionState{
108+ s := &sessions.SessionState{
108 User: "just-user",
109 User: "just-user",
109 Email: "user@domain.com",
110 Email: "user@domain.com",
110 AccessToken: "token1234",
111 AccessToken: "token1234",
@@ -115,7 +116,7 @@ func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
115 assert.Equal(t, nil, err)
116 assert.Equal(t, nil, err)
116
117
117 // only email should have been serialized
118 // only email should have been serialized
118− ss, err := DecodeSessionState(encoded, nil)
119+ ss, err := sessions.DecodeSessionState(encoded, nil)
119 assert.Equal(t, nil, err)
120 assert.Equal(t, nil, err)
120 assert.Equal(t, s.User, ss.User)
121 assert.Equal(t, s.User, ss.User)
121 assert.Equal(t, s.Email, ss.Email)
122 assert.Equal(t, s.Email, ss.Email)
@@ -124,18 +125,18 @@ func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
124}
125}
125
126
126func TestExpired(t *testing.T) {
127func TestExpired(t *testing.T) {
127− s := &SessionState{ExpiresOn: time.Now().Add(time.Duration(-1) * time.Minute)}
128+ s := &sessions.SessionState{ExpiresOn: time.Now().Add(time.Duration(-1) * time.Minute)}
128 assert.Equal(t, true, s.IsExpired())
129 assert.Equal(t, true, s.IsExpired())
129
130
130− s = &SessionState{ExpiresOn: time.Now().Add(time.Duration(1) * time.Minute)}
131+ s = &sessions.SessionState{ExpiresOn: time.Now().Add(time.Duration(1) * time.Minute)}
131 assert.Equal(t, false, s.IsExpired())
132 assert.Equal(t, false, s.IsExpired())
132
133
133− s = &SessionState{}
134+ s = &sessions.SessionState{}
134 assert.Equal(t, false, s.IsExpired())
135 assert.Equal(t, false, s.IsExpired())
135}
136}
136
137
137type testCase struct {
138type testCase struct {
138− SessionState
139+ sessions.SessionState
139 Encoded string
140 Encoded string
140 Cipher *cookie.Cipher
141 Cipher *cookie.Cipher
141 Error bool
142 Error bool
@@ -150,14 +151,14 @@ func TestEncodeSessionState(t *testing.T) {
150
151
151 testCases := []testCase{
152 testCases := []testCase{
152 {
153 {
153− SessionState: SessionState{
154+ SessionState: sessions.SessionState{
154 Email: "user@domain.com",
155 Email: "user@domain.com",
155 User: "just-user",
156 User: "just-user",
156 },
157 },
157 Encoded: `{"Email":"user@domain.com","User":"just-user"}`,
158 Encoded: `{"Email":"user@domain.com","User":"just-user"}`,
158 },
159 },
159 {
160 {
160− SessionState: SessionState{
161+ SessionState: sessions.SessionState{
161 Email: "user@domain.com",
162 Email: "user@domain.com",
162 User: "just-user",
163 User: "just-user",
163 AccessToken: "token1234",
164 AccessToken: "token1234",
@@ -171,7 +172,7 @@ func TestEncodeSessionState(t *testing.T) {
171
172
172 for i, tc := range testCases {
173 for i, tc := range testCases {
173 encoded, err := tc.EncodeSessionState(tc.Cipher)
174 encoded, err := tc.EncodeSessionState(tc.Cipher)
174− t.Logf("i:%d Encoded:%#v SessionState:%#v Error:%#v", i, encoded, tc.SessionState, err)
175+ t.Logf("i:%d Encoded:%#vsessions.SessionState:%#v Error:%#v", i, encoded, tc.SessionState, err)
175 if tc.Error {
176 if tc.Error {
176 assert.Error(t, err)
177 assert.Error(t, err)
177 assert.Empty(t, encoded)
178 assert.Empty(t, encoded)
@@ -182,7 +183,7 @@ func TestEncodeSessionState(t *testing.T) {
182 }
183 }
183}
184}
184
185
185−// TestDecodeSessionState tests DecodeSessionState with the test vector
186+// TestDecodeSessionState testssessions.DecodeSessionState with the test vector
186func TestDecodeSessionState(t *testing.T) {
187func TestDecodeSessionState(t *testing.T) {
187 e := time.Now().Add(time.Duration(1) * time.Hour)
188 e := time.Now().Add(time.Duration(1) * time.Hour)
188 eJSON, _ := e.MarshalJSON()
189 eJSON, _ := e.MarshalJSON()
@@ -194,34 +195,34 @@ func TestDecodeSessionState(t *testing.T) {
194
195
195 testCases := []testCase{
196 testCases := []testCase{
196 {
197 {
197− SessionState: SessionState{
198+ SessionState: sessions.SessionState{
198 Email: "user@domain.com",
199 Email: "user@domain.com",
199 User: "just-user",
200 User: "just-user",
200 },
201 },
201 Encoded: `{"Email":"user@domain.com","User":"just-user"}`,
202 Encoded: `{"Email":"user@domain.com","User":"just-user"}`,
202 },
203 },
203 {
204 {
204− SessionState: SessionState{
205+ SessionState: sessions.SessionState{
205 Email: "user@domain.com",
206 Email: "user@domain.com",
206 User: "user@domain.com",
207 User: "user@domain.com",
207 },
208 },
208 Encoded: `{"Email":"user@domain.com"}`,
209 Encoded: `{"Email":"user@domain.com"}`,
209 },
210 },
210 {
211 {
211− SessionState: SessionState{
212+ SessionState: sessions.SessionState{
212 User: "just-user",
213 User: "just-user",
213 },
214 },
214 Encoded: `{"User":"just-user"}`,
215 Encoded: `{"User":"just-user"}`,
215 },
216 },
216 {
217 {
217− SessionState: SessionState{
218+ SessionState: sessions.SessionState{
218 Email: "user@domain.com",
219 Email: "user@domain.com",
219 User: "just-user",
220 User: "just-user",
220 },
221 },
221 Encoded: fmt.Sprintf(`{"Email":"user@domain.com","User":"just-user","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","ExpiresOn":%s}`, eString),
222 Encoded: fmt.Sprintf(`{"Email":"user@domain.com","User":"just-user","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","ExpiresOn":%s}`, eString),
222 },
223 },
223 {
224 {
224− SessionState: SessionState{
225+ SessionState: sessions.SessionState{
225 Email: "user@domain.com",
226 Email: "user@domain.com",
226 User: "just-user",
227 User: "just-user",
227 AccessToken: "token1234",
228 AccessToken: "token1234",
@@ -233,7 +234,7 @@ func TestDecodeSessionState(t *testing.T) {
233 Cipher: c,
234 Cipher: c,
234 },
235 },
235 {
236 {
236− SessionState: SessionState{
237+ SessionState: sessions.SessionState{
237 Email: "user@domain.com",
238 Email: "user@domain.com",
238 User: "just-user",
239 User: "just-user",
239 },
240 },
@@ -251,7 +252,7 @@ func TestDecodeSessionState(t *testing.T) {
251 Error: true,
252 Error: true,
252 },
253 },
253 {
254 {
254− SessionState: SessionState{
255+ SessionState: sessions.SessionState{
255 User: "just-user",
256 User: "just-user",
256 Email: "user@domain.com",
257 Email: "user@domain.com",
257 },
258 },
@@ -272,7 +273,7 @@ func TestDecodeSessionState(t *testing.T) {
272 Error: true,
273 Error: true,
273 },
274 },
274 {
275 {
275− SessionState: SessionState{
276+ SessionState: sessions.SessionState{
276 Email: "user@domain.com",
277 Email: "user@domain.com",
277 User: "just-user",
278 User: "just-user",
278 AccessToken: "token1234",
279 AccessToken: "token1234",
@@ -283,7 +284,7 @@ func TestDecodeSessionState(t *testing.T) {
283 Cipher: c,
284 Cipher: c,
284 },
285 },
285 {
286 {
286− SessionState: SessionState{
287+ SessionState: sessions.SessionState{
287 Email: "user@domain.com",
288 Email: "user@domain.com",
288 User: "just-user",
289 User: "just-user",
289 AccessToken: "token1234",
290 AccessToken: "token1234",
@@ -297,8 +298,8 @@ func TestDecodeSessionState(t *testing.T) {
297 }
298 }
298
299
299 for i, tc := range testCases {
300 for i, tc := range testCases {
300− ss, err := DecodeSessionState(tc.Encoded, tc.Cipher)
301+ ss, err := sessions.DecodeSessionState(tc.Encoded, tc.Cipher)
301− t.Logf("i:%d Encoded:%#v SessionState:%#v Error:%#v", i, tc.Encoded, ss, err)
302+ t.Logf("i:%d Encoded:%#vsessions.SessionState:%#v Error:%#v", i, tc.Encoded, ss, err)
302 if tc.Error {
303 if tc.Error {
303 assert.Error(t, err)
304 assert.Error(t, err)
304 assert.Nil(t, ss)
305 assert.Nil(t, ss)
providers/azure.go+2−1
@@ -9,6 +9,7 @@ import (
9 "github.com/bitly/go-simplejson"
9 "github.com/bitly/go-simplejson"
10 "github.com/pusher/oauth2_proxy/api"
10 "github.com/pusher/oauth2_proxy/api"
11 "github.com/pusher/oauth2_proxy/logger"
11 "github.com/pusher/oauth2_proxy/logger"
12+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
12)
13)
13
14
14// AzureProvider represents an Azure based Identity Provider
15// AzureProvider represents an Azure based Identity Provider
@@ -88,7 +89,7 @@ func getEmailFromJSON(json *simplejson.Json) (string, error) {
88}
89}
89
90
90// GetEmailAddress returns the Account email address
91// GetEmailAddress returns the Account email address
91−func (p *AzureProvider) GetEmailAddress(s *SessionState) (string, error) {
92+func (p *AzureProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
92 var email string
93 var email string
93 var err error
94 var err error
94
95
providers/azure_test.go+7−6
@@ -6,6 +6,7 @@ import (
6 "net/url"
6 "net/url"
7 "testing"
7 "testing"
8
8
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/assert"
10)
11)
11
12
@@ -128,7 +129,7 @@ func TestAzureProviderGetEmailAddress(t *testing.T) {
128 bURL, _ := url.Parse(b.URL)
129 bURL, _ := url.Parse(b.URL)
129 p := testAzureProvider(bURL.Host)
130 p := testAzureProvider(bURL.Host)
130
131
131− session := &SessionState{AccessToken: "imaginary_access_token"}
132+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
132 email, err := p.GetEmailAddress(session)
133 email, err := p.GetEmailAddress(session)
133 assert.Equal(t, nil, err)
134 assert.Equal(t, nil, err)
134 assert.Equal(t, "user@windows.net", email)
135 assert.Equal(t, "user@windows.net", email)
@@ -141,7 +142,7 @@ func TestAzureProviderGetEmailAddressMailNull(t *testing.T) {
141 bURL, _ := url.Parse(b.URL)
142 bURL, _ := url.Parse(b.URL)
142 p := testAzureProvider(bURL.Host)
143 p := testAzureProvider(bURL.Host)
143
144
144− session := &SessionState{AccessToken: "imaginary_access_token"}
145+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
145 email, err := p.GetEmailAddress(session)
146 email, err := p.GetEmailAddress(session)
146 assert.Equal(t, nil, err)
147 assert.Equal(t, nil, err)
147 assert.Equal(t, "user@windows.net", email)
148 assert.Equal(t, "user@windows.net", email)
@@ -154,7 +155,7 @@ func TestAzureProviderGetEmailAddressGetUserPrincipalName(t *testing.T) {
154 bURL, _ := url.Parse(b.URL)
155 bURL, _ := url.Parse(b.URL)
155 p := testAzureProvider(bURL.Host)
156 p := testAzureProvider(bURL.Host)
156
157
157− session := &SessionState{AccessToken: "imaginary_access_token"}
158+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
158 email, err := p.GetEmailAddress(session)
159 email, err := p.GetEmailAddress(session)
159 assert.Equal(t, nil, err)
160 assert.Equal(t, nil, err)
160 assert.Equal(t, "user@windows.net", email)
161 assert.Equal(t, "user@windows.net", email)
@@ -167,7 +168,7 @@ func TestAzureProviderGetEmailAddressFailToGetEmailAddress(t *testing.T) {
167 bURL, _ := url.Parse(b.URL)
168 bURL, _ := url.Parse(b.URL)
168 p := testAzureProvider(bURL.Host)
169 p := testAzureProvider(bURL.Host)
169
170
170− session := &SessionState{AccessToken: "imaginary_access_token"}
171+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
171 email, err := p.GetEmailAddress(session)
172 email, err := p.GetEmailAddress(session)
172 assert.Equal(t, "type assertion to string failed", err.Error())
173 assert.Equal(t, "type assertion to string failed", err.Error())
173 assert.Equal(t, "", email)
174 assert.Equal(t, "", email)
@@ -180,7 +181,7 @@ func TestAzureProviderGetEmailAddressEmptyUserPrincipalName(t *testing.T) {
180 bURL, _ := url.Parse(b.URL)
181 bURL, _ := url.Parse(b.URL)
181 p := testAzureProvider(bURL.Host)
182 p := testAzureProvider(bURL.Host)
182
183
183− session := &SessionState{AccessToken: "imaginary_access_token"}
184+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
184 email, err := p.GetEmailAddress(session)
185 email, err := p.GetEmailAddress(session)
185 assert.Equal(t, nil, err)
186 assert.Equal(t, nil, err)
186 assert.Equal(t, "", email)
187 assert.Equal(t, "", email)
@@ -193,7 +194,7 @@ func TestAzureProviderGetEmailAddressIncorrectOtherMails(t *testing.T) {
193 bURL, _ := url.Parse(b.URL)
194 bURL, _ := url.Parse(b.URL)
194 p := testAzureProvider(bURL.Host)
195 p := testAzureProvider(bURL.Host)
195
196
196− session := &SessionState{AccessToken: "imaginary_access_token"}
197+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
197 email, err := p.GetEmailAddress(session)
198 email, err := p.GetEmailAddress(session)
198 assert.Equal(t, "type assertion to string failed", err.Error())
199 assert.Equal(t, "type assertion to string failed", err.Error())
199 assert.Equal(t, "", email)
200 assert.Equal(t, "", email)
providers/facebook.go+3−2
@@ -7,6 +7,7 @@ import (
7 "net/url"
7 "net/url"
8
8
9 "github.com/pusher/oauth2_proxy/api"
9 "github.com/pusher/oauth2_proxy/api"
10+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
10)
11)
11
12
12// FacebookProvider represents an Facebook based Identity Provider
13// FacebookProvider represents an Facebook based Identity Provider
@@ -54,7 +55,7 @@ func getFacebookHeader(accessToken string) http.Header {
54}
55}
55
56
56// GetEmailAddress returns the Account email address
57// GetEmailAddress returns the Account email address
57−func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) {
58+func (p *FacebookProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
58 if s.AccessToken == "" {
59 if s.AccessToken == "" {
59 return "", errors.New("missing access token")
60 return "", errors.New("missing access token")
60 }
61 }
@@ -79,6 +80,6 @@ func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) {
79}
80}
80
81
81// ValidateSessionState validates the AccessToken
82// ValidateSessionState validates the AccessToken
82−func (p *FacebookProvider) ValidateSessionState(s *SessionState) bool {
83+func (p *FacebookProvider) ValidateSessionState(s *sessions.SessionState) bool {
83 return validateToken(p, s.AccessToken, getFacebookHeader(s.AccessToken))
84 return validateToken(p, s.AccessToken, getFacebookHeader(s.AccessToken))
84}
85}
providers/github.go+3−2
@@ -11,6 +11,7 @@ import (
11 "strings"
11 "strings"
12
12
13 "github.com/pusher/oauth2_proxy/logger"
13 "github.com/pusher/oauth2_proxy/logger"
14+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
14)
15)
15
16
16// GitHubProvider represents an GitHub based Identity Provider
17// GitHubProvider represents an GitHub based Identity Provider
@@ -200,7 +201,7 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
200}
201}
201
202
202// GetEmailAddress returns the Account email address
203// GetEmailAddress returns the Account email address
203−func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) {
204+func (p *GitHubProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
204
205
205 var emails []struct {
206 var emails []struct {
206 Email string `json:"email"`
207 Email string `json:"email"`
@@ -259,7 +260,7 @@ func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) {
259}
260}
260
261
261// GetUserName returns the Account user name
262// GetUserName returns the Account user name
262−func (p *GitHubProvider) GetUserName(s *SessionState) (string, error) {
263+func (p *GitHubProvider) GetUserName(s *sessions.SessionState) (string, error) {
263 var user struct {
264 var user struct {
264 Login string `json:"login"`
265 Login string `json:"login"`
265 Email string `json:"email"`
266 Email string `json:"email"`
providers/github_test.go+7−6
@@ -6,6 +6,7 @@ import (
6 "net/url"
6 "net/url"
7 "testing"
7 "testing"
8
8
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/assert"
10)
11)
11
12
@@ -103,7 +104,7 @@ func TestGitHubProviderGetEmailAddress(t *testing.T) {
103 bURL, _ := url.Parse(b.URL)
104 bURL, _ := url.Parse(b.URL)
104 p := testGitHubProvider(bURL.Host)
105 p := testGitHubProvider(bURL.Host)
105
106
106− session := &SessionState{AccessToken: "imaginary_access_token"}
107+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
107 email, err := p.GetEmailAddress(session)
108 email, err := p.GetEmailAddress(session)
108 assert.Equal(t, nil, err)
109 assert.Equal(t, nil, err)
109 assert.Equal(t, "michael.bland@gsa.gov", email)
110 assert.Equal(t, "michael.bland@gsa.gov", email)
@@ -116,7 +117,7 @@ func TestGitHubProviderGetEmailAddressNotVerified(t *testing.T) {
116 bURL, _ := url.Parse(b.URL)
117 bURL, _ := url.Parse(b.URL)
117 p := testGitHubProvider(bURL.Host)
118 p := testGitHubProvider(bURL.Host)
118
119
119− session := &SessionState{AccessToken: "imaginary_access_token"}
120+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
120 email, err := p.GetEmailAddress(session)
121 email, err := p.GetEmailAddress(session)
121 assert.Equal(t, nil, err)
122 assert.Equal(t, nil, err)
122 assert.Empty(t, "", email)
123 assert.Empty(t, "", email)
@@ -134,7 +135,7 @@ func TestGitHubProviderGetEmailAddressWithOrg(t *testing.T) {
134 p := testGitHubProvider(bURL.Host)
135 p := testGitHubProvider(bURL.Host)
135 p.Org = "testorg1"
136 p.Org = "testorg1"
136
137
137− session := &SessionState{AccessToken: "imaginary_access_token"}
138+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
138 email, err := p.GetEmailAddress(session)
139 email, err := p.GetEmailAddress(session)
139 assert.Equal(t, nil, err)
140 assert.Equal(t, nil, err)
140 assert.Equal(t, "michael.bland@gsa.gov", email)
141 assert.Equal(t, "michael.bland@gsa.gov", email)
@@ -152,7 +153,7 @@ func TestGitHubProviderGetEmailAddressFailedRequest(t *testing.T) {
152 // We'll trigger a request failure by using an unexpected access
153 // We'll trigger a request failure by using an unexpected access
153 // token. Alternatively, we could allow the parsing of the payload as
154 // token. Alternatively, we could allow the parsing of the payload as
154 // JSON to fail.
155 // JSON to fail.
155− session := &SessionState{AccessToken: "unexpected_access_token"}
156+ session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
156 email, err := p.GetEmailAddress(session)
157 email, err := p.GetEmailAddress(session)
157 assert.NotEqual(t, nil, err)
158 assert.NotEqual(t, nil, err)
158 assert.Equal(t, "", email)
159 assert.Equal(t, "", email)
@@ -165,7 +166,7 @@ func TestGitHubProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
165 bURL, _ := url.Parse(b.URL)
166 bURL, _ := url.Parse(b.URL)
166 p := testGitHubProvider(bURL.Host)
167 p := testGitHubProvider(bURL.Host)
167
168
168− session := &SessionState{AccessToken: "imaginary_access_token"}
169+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
169 email, err := p.GetEmailAddress(session)
170 email, err := p.GetEmailAddress(session)
170 assert.NotEqual(t, nil, err)
171 assert.NotEqual(t, nil, err)
171 assert.Equal(t, "", email)
172 assert.Equal(t, "", email)
@@ -178,7 +179,7 @@ func TestGitHubProviderGetUserName(t *testing.T) {
178 bURL, _ := url.Parse(b.URL)
179 bURL, _ := url.Parse(b.URL)
179 p := testGitHubProvider(bURL.Host)
180 p := testGitHubProvider(bURL.Host)
180
181
181− session := &SessionState{AccessToken: "imaginary_access_token"}
182+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
182 email, err := p.GetUserName(session)
183 email, err := p.GetUserName(session)
183 assert.Equal(t, nil, err)
184 assert.Equal(t, nil, err)
184 assert.Equal(t, "mbland", email)
185 assert.Equal(t, "mbland", email)
providers/gitlab.go+2−1
@@ -6,6 +6,7 @@ import (
6
6
7 "github.com/pusher/oauth2_proxy/api"
7 "github.com/pusher/oauth2_proxy/api"
8 "github.com/pusher/oauth2_proxy/logger"
8 "github.com/pusher/oauth2_proxy/logger"
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9)
10)
10
11
11// GitLabProvider represents an GitLab based Identity Provider
12// GitLabProvider represents an GitLab based Identity Provider
@@ -44,7 +45,7 @@ func NewGitLabProvider(p *ProviderData) *GitLabProvider {
44}
45}
45
46
46// GetEmailAddress returns the Account email address
47// GetEmailAddress returns the Account email address
47−func (p *GitLabProvider) GetEmailAddress(s *SessionState) (string, error) {
48+func (p *GitLabProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
48
49
49 req, err := http.NewRequest("GET",
50 req, err := http.NewRequest("GET",
50 p.ValidateURL.String()+"?access_token="+s.AccessToken, nil)
51 p.ValidateURL.String()+"?access_token="+s.AccessToken, nil)
providers/gitlab_test.go+4−3
@@ -6,6 +6,7 @@ import (
6 "net/url"
6 "net/url"
7 "testing"
7 "testing"
8
8
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/assert"
10)
11)
11
12
@@ -89,7 +90,7 @@ func TestGitLabProviderGetEmailAddress(t *testing.T) {
89 bURL, _ := url.Parse(b.URL)
90 bURL, _ := url.Parse(b.URL)
90 p := testGitLabProvider(bURL.Host)
91 p := testGitLabProvider(bURL.Host)
91
92
92− session := &SessionState{AccessToken: "imaginary_access_token"}
93+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
93 email, err := p.GetEmailAddress(session)
94 email, err := p.GetEmailAddress(session)
94 assert.Equal(t, nil, err)
95 assert.Equal(t, nil, err)
95 assert.Equal(t, "michael.bland@gsa.gov", email)
96 assert.Equal(t, "michael.bland@gsa.gov", email)
@@ -107,7 +108,7 @@ func TestGitLabProviderGetEmailAddressFailedRequest(t *testing.T) {
107 // We'll trigger a request failure by using an unexpected access
108 // We'll trigger a request failure by using an unexpected access
108 // token. Alternatively, we could allow the parsing of the payload as
109 // token. Alternatively, we could allow the parsing of the payload as
109 // JSON to fail.
110 // JSON to fail.
110− session := &SessionState{AccessToken: "unexpected_access_token"}
111+ session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
111 email, err := p.GetEmailAddress(session)
112 email, err := p.GetEmailAddress(session)
112 assert.NotEqual(t, nil, err)
113 assert.NotEqual(t, nil, err)
113 assert.Equal(t, "", email)
114 assert.Equal(t, "", email)
@@ -120,7 +121,7 @@ func TestGitLabProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
120 bURL, _ := url.Parse(b.URL)
121 bURL, _ := url.Parse(b.URL)
121 p := testGitLabProvider(bURL.Host)
122 p := testGitLabProvider(bURL.Host)
122
123
123− session := &SessionState{AccessToken: "imaginary_access_token"}
124+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
124 email, err := p.GetEmailAddress(session)
125 email, err := p.GetEmailAddress(session)
125 assert.NotEqual(t, nil, err)
126 assert.NotEqual(t, nil, err)
126 assert.Equal(t, "", email)
127 assert.Equal(t, "", email)
providers/google.go+4−3
@@ -14,6 +14,7 @@ import (
14 "time"
14 "time"
15
15
16 "github.com/pusher/oauth2_proxy/logger"
16 "github.com/pusher/oauth2_proxy/logger"
17+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
17 "golang.org/x/oauth2"
18 "golang.org/x/oauth2"
18 "golang.org/x/oauth2/google"
19 "golang.org/x/oauth2/google"
19 admin "google.golang.org/api/admin/directory/v1"
20 admin "google.golang.org/api/admin/directory/v1"
@@ -96,7 +97,7 @@ func claimsFromIDToken(idToken string) (*claims, error) {
96}
97}
97
98
98// Redeem exchanges the OAuth2 authentication token for an ID token
99// Redeem exchanges the OAuth2 authentication token for an ID token
99−func (p *GoogleProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
100+func (p *GoogleProvider) Redeem(redirectURL, code string) (s *sessions.SessionState, err error) {
100 if code == "" {
101 if code == "" {
101 err = errors.New("missing code")
102 err = errors.New("missing code")
102 return
103 return
@@ -145,7 +146,7 @@ func (p *GoogleProvider) Redeem(redirectURL, code string) (s *SessionState, err
145 if err != nil {
146 if err != nil {
146 return
147 return
147 }
148 }
148− s = &SessionState{
149+ s = &sessions.SessionState{
149 AccessToken: jsonResponse.AccessToken,
150 AccessToken: jsonResponse.AccessToken,
150 IDToken: jsonResponse.IDToken,
151 IDToken: jsonResponse.IDToken,
151 ExpiresOn: time.Now().Add(time.Duration(jsonResponse.ExpiresIn) * time.Second).Truncate(time.Second),
152 ExpiresOn: time.Now().Add(time.Duration(jsonResponse.ExpiresIn) * time.Second).Truncate(time.Second),
@@ -258,7 +259,7 @@ func (p *GoogleProvider) ValidateGroup(email string) bool {
258
259
259// RefreshSessionIfNeeded checks if the session has expired and uses the
260// RefreshSessionIfNeeded checks if the session has expired and uses the
260// RefreshToken to fetch a new ID token if required
261// RefreshToken to fetch a new ID token if required
261−func (p *GoogleProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
262+func (p *GoogleProvider) RefreshSessionIfNeeded(s *sessions.SessionState) (bool, error) {
262 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
263 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
263 return false, nil
264 return false, nil
264 }
265 }
providers/internal_util_test.go+3−2
@@ -7,6 +7,7 @@ import (
7 "net/url"
7 "net/url"
8 "testing"
8 "testing"
9
9
10+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/assert"
11)
12)
12
13
@@ -19,13 +20,13 @@ type ValidateSessionStateTestProvider struct {
19 *ProviderData
20 *ProviderData
20}
21}
21
22
22−func (tp *ValidateSessionStateTestProvider) GetEmailAddress(s *SessionState) (string, error) {
23+func (tp *ValidateSessionStateTestProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
23 return "", errors.New("not implemented")
24 return "", errors.New("not implemented")
24}
25}
25
26
26// Note that we're testing the internal validateToken() used to implement
27// Note that we're testing the internal validateToken() used to implement
27// several Provider's ValidateSessionState() implementations
28// several Provider's ValidateSessionState() implementations
28−func (tp *ValidateSessionStateTestProvider) ValidateSessionState(s *SessionState) bool {
29+func (tp *ValidateSessionStateTestProvider) ValidateSessionState(s *sessions.SessionState) bool {
29 return false
30 return false
30}
31}
31
32
providers/linkedin.go+3−2
@@ -7,6 +7,7 @@ import (
7 "net/url"
7 "net/url"
8
8
9 "github.com/pusher/oauth2_proxy/api"
9 "github.com/pusher/oauth2_proxy/api"
10+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
10)
11)
11
12
12// LinkedInProvider represents an LinkedIn based Identity Provider
13// LinkedInProvider represents an LinkedIn based Identity Provider
@@ -50,7 +51,7 @@ func getLinkedInHeader(accessToken string) http.Header {
50}
51}
51
52
52// GetEmailAddress returns the Account email address
53// GetEmailAddress returns the Account email address
53−func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) {
54+func (p *LinkedInProvider) GetEmailAddress(s *sessions.SessionState) (string, error) {
54 if s.AccessToken == "" {
55 if s.AccessToken == "" {
55 return "", errors.New("missing access token")
56 return "", errors.New("missing access token")
56 }
57 }
@@ -73,6 +74,6 @@ func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) {
73}
74}
74
75
75// ValidateSessionState validates the AccessToken
76// ValidateSessionState validates the AccessToken
76−func (p *LinkedInProvider) ValidateSessionState(s *SessionState) bool {
77+func (p *LinkedInProvider) ValidateSessionState(s *sessions.SessionState) bool {
77 return validateToken(p, s.AccessToken, getLinkedInHeader(s.AccessToken))
78 return validateToken(p, s.AccessToken, getLinkedInHeader(s.AccessToken))
78}
79}
providers/linkedin_test.go+4−3
@@ -6,6 +6,7 @@ import (
6 "net/url"
6 "net/url"
7 "testing"
7 "testing"
8
8
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/assert"
10)
11)
11
12
@@ -97,7 +98,7 @@ func TestLinkedInProviderGetEmailAddress(t *testing.T) {
97 bURL, _ := url.Parse(b.URL)
98 bURL, _ := url.Parse(b.URL)
98 p := testLinkedInProvider(bURL.Host)
99 p := testLinkedInProvider(bURL.Host)
99
100
100− session := &SessionState{AccessToken: "imaginary_access_token"}
101+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
101 email, err := p.GetEmailAddress(session)
102 email, err := p.GetEmailAddress(session)
102 assert.Equal(t, nil, err)
103 assert.Equal(t, nil, err)
103 assert.Equal(t, "user@linkedin.com", email)
104 assert.Equal(t, "user@linkedin.com", email)
@@ -113,7 +114,7 @@ func TestLinkedInProviderGetEmailAddressFailedRequest(t *testing.T) {
113 // We'll trigger a request failure by using an unexpected access
114 // We'll trigger a request failure by using an unexpected access
114 // token. Alternatively, we could allow the parsing of the payload as
115 // token. Alternatively, we could allow the parsing of the payload as
115 // JSON to fail.
116 // JSON to fail.
116− session := &SessionState{AccessToken: "unexpected_access_token"}
117+ session := &sessions.SessionState{AccessToken: "unexpected_access_token"}
117 email, err := p.GetEmailAddress(session)
118 email, err := p.GetEmailAddress(session)
118 assert.NotEqual(t, nil, err)
119 assert.NotEqual(t, nil, err)
119 assert.Equal(t, "", email)
120 assert.Equal(t, "", email)
@@ -126,7 +127,7 @@ func TestLinkedInProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) {
126 bURL, _ := url.Parse(b.URL)
127 bURL, _ := url.Parse(b.URL)
127 p := testLinkedInProvider(bURL.Host)
128 p := testLinkedInProvider(bURL.Host)
128
129
129− session := &SessionState{AccessToken: "imaginary_access_token"}
130+ session := &sessions.SessionState{AccessToken: "imaginary_access_token"}
130 email, err := p.GetEmailAddress(session)
131 email, err := p.GetEmailAddress(session)
131 assert.NotEqual(t, nil, err)
132 assert.NotEqual(t, nil, err)
132 assert.Equal(t, "", email)
133 assert.Equal(t, "", email)
providers/logingov.go+3−2
@@ -13,6 +13,7 @@ import (
13 "time"
13 "time"
14
14
15 "github.com/dgrijalva/jwt-go"
15 "github.com/dgrijalva/jwt-go"
16+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
16 "gopkg.in/square/go-jose.v2"
17 "gopkg.in/square/go-jose.v2"
17)
18)
18
19
@@ -173,7 +174,7 @@ func emailFromUserInfo(accessToken string, userInfoEndpoint string) (email strin
173}
174}
174
175
175// Redeem exchanges the OAuth2 authentication token for an ID token
176// Redeem exchanges the OAuth2 authentication token for an ID token
176−func (p *LoginGovProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
177+func (p *LoginGovProvider) Redeem(redirectURL, code string) (s *sessions.SessionState, err error) {
177 if code == "" {
178 if code == "" {
178 err = errors.New("missing code")
179 err = errors.New("missing code")
179 return
180 return
@@ -248,7 +249,7 @@ func (p *LoginGovProvider) Redeem(redirectURL, code string) (s *SessionState, er
248 }
249 }
249
250
250 // Store the data that we found in the session state
251 // Store the data that we found in the session state
251− s = &SessionState{
252+ s = &sessions.SessionState{
252 AccessToken: jsonResponse.AccessToken,
253 AccessToken: jsonResponse.AccessToken,
253 IDToken: jsonResponse.IDToken,
254 IDToken: jsonResponse.IDToken,
254 ExpiresOn: time.Now().Add(time.Duration(jsonResponse.ExpiresIn) * time.Second).Truncate(time.Second),
255 ExpiresOn: time.Now().Add(time.Duration(jsonResponse.ExpiresIn) * time.Second).Truncate(time.Second),
providers/oidc.go+8−8
@@ -5,9 +5,9 @@ import (
5 "fmt"
5 "fmt"
6 "time"
6 "time"
7
7
8− "golang.org/x/oauth2"
9−
10 oidc "github.com/coreos/go-oidc"
8 oidc "github.com/coreos/go-oidc"
9+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
10+ "golang.org/x/oauth2"
11)
11)
12
12
13// OIDCProvider represents an OIDC based Identity Provider
13// OIDCProvider represents an OIDC based Identity Provider
@@ -24,7 +24,7 @@ func NewOIDCProvider(p *ProviderData) *OIDCProvider {
24}
24}
25
25
26// Redeem exchanges the OAuth2 authentication token for an ID token
26// Redeem exchanges the OAuth2 authentication token for an ID token
27−func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err error) {
27+func (p *OIDCProvider) Redeem(redirectURL, code string) (s *sessions.SessionState, err error) {
28 ctx := context.Background()
28 ctx := context.Background()
29 c := oauth2.Config{
29 c := oauth2.Config{
30 ClientID: p.ClientID,
30 ClientID: p.ClientID,
@@ -47,7 +47,7 @@ func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err er
47
47
48// RefreshSessionIfNeeded checks if the session has expired and uses the
48// RefreshSessionIfNeeded checks if the session has expired and uses the
49// RefreshToken to fetch a new ID token if required
49// RefreshToken to fetch a new ID token if required
50−func (p *OIDCProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
50+func (p *OIDCProvider) RefreshSessionIfNeeded(s *sessions.SessionState) (bool, error) {
51 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
51 if s == nil || s.ExpiresOn.After(time.Now()) || s.RefreshToken == "" {
52 return false, nil
52 return false, nil
53 }
53 }
@@ -63,7 +63,7 @@ func (p *OIDCProvider) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
63 return true, nil
63 return true, nil
64}
64}
65
65
66−func (p *OIDCProvider) redeemRefreshToken(s *SessionState) (err error) {
66+func (p *OIDCProvider) redeemRefreshToken(s *sessions.SessionState) (err error) {
67 c := oauth2.Config{
67 c := oauth2.Config{
68 ClientID: p.ClientID,
68 ClientID: p.ClientID,
69 ClientSecret: p.ClientSecret,
69 ClientSecret: p.ClientSecret,
@@ -92,7 +92,7 @@ func (p *OIDCProvider) redeemRefreshToken(s *SessionState) (err error) {
92 return
92 return
93}
93}
94
94
95−func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Token) (*SessionState, error) {
95+func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Token) (*sessions.SessionState, error) {
96 rawIDToken, ok := token.Extra("id_token").(string)
96 rawIDToken, ok := token.Extra("id_token").(string)
97 if !ok {
97 if !ok {
98 return nil, fmt.Errorf("token response did not contain an id_token")
98 return nil, fmt.Errorf("token response did not contain an id_token")
@@ -122,7 +122,7 @@ func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Tok
122 return nil, fmt.Errorf("email in id_token (%s) isn't verified", claims.Email)
122 return nil, fmt.Errorf("email in id_token (%s) isn't verified", claims.Email)
123 }
123 }
124
124
125− return &SessionState{
125+ return &sessions.SessionState{
126 AccessToken: token.AccessToken,
126 AccessToken: token.AccessToken,
127 IDToken: rawIDToken,
127 IDToken: rawIDToken,
128 RefreshToken: token.RefreshToken,
128 RefreshToken: token.RefreshToken,
@@ -133,7 +133,7 @@ func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Tok
133}
133}
134
134
135// ValidateSessionState checks that the session's IDToken is still valid
135// ValidateSessionState checks that the session's IDToken is still valid
136−func (p *OIDCProvider) ValidateSessionState(s *SessionState) bool {
136+func (p *OIDCProvider) ValidateSessionState(s *sessions.SessionState) bool {
137 ctx := context.Background()
137 ctx := context.Background()
138 _, err := p.Verifier.Verify(ctx, s.IDToken)
138 _, err := p.Verifier.Verify(ctx, s.IDToken)
139 if err != nil {
139 if err != nil {
providers/provider_default.go+11−10
@@ -10,10 +10,11 @@ import (
10 "net/url"
10 "net/url"
11
11
12 "github.com/pusher/oauth2_proxy/cookie"
12 "github.com/pusher/oauth2_proxy/cookie"
13+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
13)
14)
14
15
15// Redeem provides a default implementation of the OAuth2 token redemption process
16// Redeem provides a default implementation of the OAuth2 token redemption process
16−func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err error) {
17+func (p *ProviderData) Redeem(redirectURL, code string) (s *sessions.SessionState, err error) {
17 if code == "" {
18 if code == "" {
18 err = errors.New("missing code")
19 err = errors.New("missing code")
19 return
20 return
@@ -59,7 +60,7 @@ func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err er
59 }
60 }
60 err = json.Unmarshal(body, &jsonResponse)
61 err = json.Unmarshal(body, &jsonResponse)
61 if err == nil {
62 if err == nil {
62− s = &SessionState{
63+ s = &sessions.SessionState{
63 AccessToken: jsonResponse.AccessToken,
64 AccessToken: jsonResponse.AccessToken,
64 }
65 }
65 return
66 return
@@ -71,7 +72,7 @@ func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err er
71 return
72 return
72 }
73 }
73 if a := v.Get("access_token"); a != "" {
74 if a := v.Get("access_token"); a != "" {
74− s = &SessionState{AccessToken: a}
75+ s = &sessions.SessionState{AccessToken: a}
75 } else {
76 } else {
76 err = fmt.Errorf("no access token found %s", body)
77 err = fmt.Errorf("no access token found %s", body)
77 }
78 }
@@ -94,22 +95,22 @@ func (p *ProviderData) GetLoginURL(redirectURI, state string) string {
94}
95}
95
96
96// CookieForSession serializes a session state for storage in a cookie
97// CookieForSession serializes a session state for storage in a cookie
97−func (p *ProviderData) CookieForSession(s *SessionState, c *cookie.Cipher) (string, error) {
98+func (p *ProviderData) CookieForSession(s *sessions.SessionState, c *cookie.Cipher) (string, error) {
98 return s.EncodeSessionState(c)
99 return s.EncodeSessionState(c)
99}
100}
100
101
101// SessionFromCookie deserializes a session from a cookie value
102// SessionFromCookie deserializes a session from a cookie value
102−func (p *ProviderData) SessionFromCookie(v string, c *cookie.Cipher) (s *SessionState, err error) {
103+func (p *ProviderData) SessionFromCookie(v string, c *cookie.Cipher) (s *sessions.SessionState, err error) {
103− return DecodeSessionState(v, c)
104+ return sessions.DecodeSessionState(v, c)
104}
105}
105
106
106// GetEmailAddress returns the Account email address
107// GetEmailAddress returns the Account email address
107−func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) {
108+func (p *ProviderData) GetEmailAddress(s *sessions.SessionState) (string, error) {
108 return "", errors.New("not implemented")
109 return "", errors.New("not implemented")
109}
110}
110
111
111// GetUserName returns the Account username
112// GetUserName returns the Account username
112−func (p *ProviderData) GetUserName(s *SessionState) (string, error) {
113+func (p *ProviderData) GetUserName(s *sessions.SessionState) (string, error) {
113 return "", errors.New("not implemented")
114 return "", errors.New("not implemented")
114}
115}
115
116
@@ -120,12 +121,12 @@ func (p *ProviderData) ValidateGroup(email string) bool {
120}
121}
121
122
122// ValidateSessionState validates the AccessToken
123// ValidateSessionState validates the AccessToken
123−func (p *ProviderData) ValidateSessionState(s *SessionState) bool {
124+func (p *ProviderData) ValidateSessionState(s *sessions.SessionState) bool {
124 return validateToken(p, s.AccessToken, nil)
125 return validateToken(p, s.AccessToken, nil)
125}
126}
126
127
127// RefreshSessionIfNeeded should refresh the user's session if required and
128// RefreshSessionIfNeeded should refresh the user's session if required and
128// do nothing if a refresh is not required
129// do nothing if a refresh is not required
129−func (p *ProviderData) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
130+func (p *ProviderData) RefreshSessionIfNeeded(s *sessions.SessionState) (bool, error) {
130 return false, nil
131 return false, nil
131}
132}
providers/provider_default_test.go+2−1
@@ -4,12 +4,13 @@ import (
4 "testing"
4 "testing"
5 "time"
5 "time"
6
6
7+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
7 "github.com/stretchr/testify/assert"
8 "github.com/stretchr/testify/assert"
8)
9)
9
10
10func TestRefresh(t *testing.T) {
11func TestRefresh(t *testing.T) {
11 p := &ProviderData{}
12 p := &ProviderData{}
12− refreshed, err := p.RefreshSessionIfNeeded(&SessionState{
13+ refreshed, err := p.RefreshSessionIfNeeded(&sessions.SessionState{
13 ExpiresOn: time.Now().Add(time.Duration(-11) * time.Minute),
14 ExpiresOn: time.Now().Add(time.Duration(-11) * time.Minute),
14 })
15 })
15 assert.Equal(t, false, refreshed)
16 assert.Equal(t, false, refreshed)
providers/providers.go+8−7
@@ -2,20 +2,21 @@ package providers
2
2
3import (
3import (
4 "github.com/pusher/oauth2_proxy/cookie"
4 "github.com/pusher/oauth2_proxy/cookie"
5+ "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
5)
6)
6
7
7// Provider represents an upstream identity provider implementation
8// Provider represents an upstream identity provider implementation
8type Provider interface {
9type Provider interface {
9 Data() *ProviderData
10 Data() *ProviderData
10− GetEmailAddress(*SessionState) (string, error)
11+ GetEmailAddress(*sessions.SessionState) (string, error)
11− GetUserName(*SessionState) (string, error)
12+ GetUserName(*sessions.SessionState) (string, error)
12− Redeem(string, string) (*SessionState, error)
13+ Redeem(string, string) (*sessions.SessionState, error)
13 ValidateGroup(string) bool
14 ValidateGroup(string) bool
14− ValidateSessionState(*SessionState) bool
15+ ValidateSessionState(*sessions.SessionState) bool
15 GetLoginURL(redirectURI, finalRedirect string) string
16 GetLoginURL(redirectURI, finalRedirect string) string
16− RefreshSessionIfNeeded(*SessionState) (bool, error)
17+ RefreshSessionIfNeeded(*sessions.SessionState) (bool, error)
17− SessionFromCookie(string, *cookie.Cipher) (*SessionState, error)
18+ SessionFromCookie(string, *cookie.Cipher) (*sessions.SessionState, error)
18− CookieForSession(*SessionState, *cookie.Cipher) (string, error)
19+ CookieForSession(*sessions.SessionState, *cookie.Cipher) (string, error)
19}
20}
20
21
21// New provides a new Provider based on the configured provider string
22// New provides a new Provider based on the configured provider string