...

Source file src/github.com/ory/fosite/handler/oauth2/flow_resource_owner_test.go

Documentation: github.com/ory/fosite/handler/oauth2

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   *
    20   */
    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  				//assert.NotEmpty(t, areq.GetSession().GetExpiresAt(fosite.AccessToken))
   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