1
21
22 package oauth2
23
24 import (
25 "fmt"
26 "net/url"
27 "testing"
28 "time"
29
30 "github.com/golang/mock/gomock"
31 "github.com/pkg/errors"
32 "github.com/stretchr/testify/assert"
33 "github.com/stretchr/testify/require"
34
35 "github.com/ory/fosite"
36 "github.com/ory/fosite/internal"
37 )
38
39 func TestResourceOwnerFlow_HandleTokenEndpointRequest(t *testing.T) {
40 ctrl := gomock.NewController(t)
41 store := internal.NewMockResourceOwnerPasswordCredentialsGrantStorage(ctrl)
42 defer ctrl.Finish()
43
44 areq := fosite.NewAccessRequest(new(fosite.DefaultSession))
45 areq.Form = url.Values{}
46
47 h := ResourceOwnerPasswordCredentialsGrantHandler{
48 ResourceOwnerPasswordCredentialsGrantStorage: store,
49 HandleHelper: &HandleHelper{
50 AccessTokenStorage: store,
51 AccessTokenLifespan: time.Hour,
52 RefreshTokenLifespan: time.Hour,
53 },
54 ScopeStrategy: fosite.HierarchicScopeStrategy,
55 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
56 }
57 for k, c := range []struct {
58 description string
59 setup func()
60 expectErr error
61 check func(areq *fosite.AccessRequest)
62 }{
63 {
64 description: "should fail because not responsible",
65 expectErr: fosite.ErrUnknownRequest,
66 setup: func() {
67 areq.GrantTypes = fosite.Arguments{"123"}
68 },
69 },
70 {
71 description: "should fail because scope missing",
72 setup: func() {
73 areq.GrantTypes = fosite.Arguments{"password"}
74 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"password"}, Scopes: []string{}}
75 areq.RequestedScope = []string{"foo-scope"}
76 },
77 expectErr: fosite.ErrInvalidScope,
78 },
79 {
80 description: "should fail because audience missing",
81 setup: func() {
82 areq.RequestedAudience = fosite.Arguments{"https://www.ory.sh/api"}
83 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"password"}, Scopes: []string{"foo-scope"}}
84 },
85 expectErr: fosite.ErrInvalidRequest,
86 },
87 {
88 description: "should fail because invalid grant_type specified",
89 setup: func() {
90 areq.GrantTypes = fosite.Arguments{"password"}
91 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"authorization_code"}, Scopes: []string{"foo-scope"}}
92 },
93 expectErr: fosite.ErrUnauthorizedClient,
94 },
95 {
96 description: "should fail because invalid credentials",
97 setup: func() {
98 areq.Form.Set("username", "peter")
99 areq.Form.Set("password", "pan")
100 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"password"}, Scopes: []string{"foo-scope"}, Audience: []string{"https://www.ory.sh/api"}}
101
102 store.EXPECT().Authenticate(nil, "peter", "pan").Return(fosite.ErrNotFound)
103 },
104 expectErr: fosite.ErrInvalidGrant,
105 },
106 {
107 description: "should fail because error on lookup",
108 setup: func() {
109 store.EXPECT().Authenticate(nil, "peter", "pan").Return(errors.New(""))
110 },
111 expectErr: fosite.ErrServerError,
112 },
113 {
114 description: "should pass",
115 setup: func() {
116 store.EXPECT().Authenticate(nil, "peter", "pan").Return(nil)
117 },
118 check: func(areq *fosite.AccessRequest) {
119
120 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken))
121 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken))
122 },
123 },
124 } {
125 t.Run(fmt.Sprintf("case=%d/description=%s", k, c.description), func(t *testing.T) {
126 c.setup()
127 err := h.HandleTokenEndpointRequest(nil, areq)
128
129 if c.expectErr != nil {
130 require.EqualError(t, err, c.expectErr.Error())
131 } else {
132 require.NoError(t, err)
133 if c.check != nil {
134 c.check(areq)
135 }
136 }
137 })
138 }
139 }
140
141 func TestResourceOwnerFlow_PopulateTokenEndpointResponse(t *testing.T) {
142 ctrl := gomock.NewController(t)
143 store := internal.NewMockResourceOwnerPasswordCredentialsGrantStorage(ctrl)
144 chgen := internal.NewMockAccessTokenStrategy(ctrl)
145 rtstr := internal.NewMockRefreshTokenStrategy(ctrl)
146 mockAT := "accesstoken.foo.bar"
147 mockRT := "refreshtoken.bar.foo"
148 defer ctrl.Finish()
149
150 var areq *fosite.AccessRequest
151 var aresp *fosite.AccessResponse
152 var h ResourceOwnerPasswordCredentialsGrantHandler
153
154 for k, c := range []struct {
155 description string
156 setup func()
157 expectErr error
158 expect func()
159 }{
160 {
161 description: "should fail because not responsible",
162 expectErr: fosite.ErrUnknownRequest,
163 setup: func() {
164 areq.GrantTypes = fosite.Arguments{""}
165 },
166 },
167 {
168 description: "should pass",
169 setup: func() {
170 areq.GrantTypes = fosite.Arguments{"password"}
171 chgen.EXPECT().GenerateAccessToken(nil, areq).Return(mockAT, "bar", nil)
172 store.EXPECT().CreateAccessTokenSession(nil, "bar", gomock.Eq(areq.Sanitize([]string{}))).Return(nil)
173 },
174 expect: func() {
175 assert.Nil(t, aresp.GetExtra("refresh_token"), "unexpected refresh token")
176 },
177 },
178 {
179 description: "should pass - offline scope",
180 setup: func() {
181 areq.GrantTypes = fosite.Arguments{"password"}
182 areq.GrantScope("offline")
183 rtstr.EXPECT().GenerateRefreshToken(nil, areq).Return(mockRT, "bar", nil)
184 store.EXPECT().CreateRefreshTokenSession(nil, "bar", gomock.Eq(areq.Sanitize([]string{}))).Return(nil)
185 chgen.EXPECT().GenerateAccessToken(nil, areq).Return(mockAT, "bar", nil)
186 store.EXPECT().CreateAccessTokenSession(nil, "bar", gomock.Eq(areq.Sanitize([]string{}))).Return(nil)
187 },
188 expect: func() {
189 assert.NotNil(t, aresp.GetExtra("refresh_token"), "expected refresh token")
190 },
191 },
192 {
193 description: "should pass - refresh token without offline scope",
194 setup: func() {
195 h.RefreshTokenScopes = []string{}
196 areq.GrantTypes = fosite.Arguments{"password"}
197 rtstr.EXPECT().GenerateRefreshToken(nil, areq).Return(mockRT, "bar", nil)
198 store.EXPECT().CreateRefreshTokenSession(nil, "bar", gomock.Eq(areq.Sanitize([]string{}))).Return(nil)
199 chgen.EXPECT().GenerateAccessToken(nil, areq).Return(mockAT, "bar", nil)
200 store.EXPECT().CreateAccessTokenSession(nil, "bar", gomock.Eq(areq.Sanitize([]string{}))).Return(nil)
201 },
202 expect: func() {
203 assert.NotNil(t, aresp.GetExtra("refresh_token"), "expected refresh token")
204 },
205 },
206 } {
207 t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
208 areq = fosite.NewAccessRequest(nil)
209 aresp = fosite.NewAccessResponse()
210 areq.Session = &fosite.DefaultSession{}
211 h = ResourceOwnerPasswordCredentialsGrantHandler{
212 ResourceOwnerPasswordCredentialsGrantStorage: store,
213 HandleHelper: &HandleHelper{
214 AccessTokenStorage: store,
215 AccessTokenStrategy: chgen,
216 AccessTokenLifespan: time.Hour,
217 },
218 RefreshTokenStrategy: rtstr,
219 RefreshTokenScopes: []string{"offline"},
220 }
221 c.setup()
222 err := h.PopulateTokenEndpointResponse(nil, areq, aresp)
223 if c.expectErr != nil {
224 require.EqualError(t, err, c.expectErr.Error())
225 } else {
226 require.NoError(t, err)
227 if c.expect != nil {
228 c.expect()
229 }
230 }
231 })
232 }
233 }
234
View as plain text