code.gitea.io/gitea@v1.21.7/models/auth/oauth2_test.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package auth_test
     5  
     6  import (
     7  	"testing"
     8  
     9  	auth_model "code.gitea.io/gitea/models/auth"
    10  	"code.gitea.io/gitea/models/db"
    11  	"code.gitea.io/gitea/models/unittest"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  //////////////////// Application
    17  
    18  func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
    19  	assert.NoError(t, unittest.PrepareTestDatabase())
    20  	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
    21  	secret, err := app.GenerateClientSecret()
    22  	assert.NoError(t, err)
    23  	assert.True(t, len(secret) > 0)
    24  	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1, ClientSecret: app.ClientSecret})
    25  }
    26  
    27  func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) {
    28  	assert.NoError(b, unittest.PrepareTestDatabase())
    29  	app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1})
    30  	for i := 0; i < b.N; i++ {
    31  		_, _ = app.GenerateClientSecret()
    32  	}
    33  }
    34  
    35  func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
    36  	app := &auth_model.OAuth2Application{
    37  		RedirectURIs: []string{"a", "b", "c"},
    38  	}
    39  	assert.True(t, app.ContainsRedirectURI("a"))
    40  	assert.True(t, app.ContainsRedirectURI("b"))
    41  	assert.True(t, app.ContainsRedirectURI("c"))
    42  	assert.False(t, app.ContainsRedirectURI("d"))
    43  }
    44  
    45  func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
    46  	app := &auth_model.OAuth2Application{
    47  		RedirectURIs:       []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
    48  		ConfidentialClient: false,
    49  	}
    50  
    51  	// http loopback uris should ignore port
    52  	// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
    53  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
    54  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
    55  	assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
    56  
    57  	// not http
    58  	assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
    59  	// not loopback
    60  	assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
    61  	assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
    62  	// unparseable
    63  	assert.False(t, app.ContainsRedirectURI(":"))
    64  }
    65  
    66  func TestOAuth2Application_ContainsRedirect_Slash(t *testing.T) {
    67  	app := &auth_model.OAuth2Application{RedirectURIs: []string{"http://127.0.0.1"}}
    68  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1"))
    69  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
    70  	assert.False(t, app.ContainsRedirectURI("http://127.0.0.1/other"))
    71  
    72  	app = &auth_model.OAuth2Application{RedirectURIs: []string{"http://127.0.0.1/"}}
    73  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1"))
    74  	assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
    75  	assert.False(t, app.ContainsRedirectURI("http://127.0.0.1/other"))
    76  }
    77  
    78  func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
    79  	assert.NoError(t, unittest.PrepareTestDatabase())
    80  	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
    81  	secret, err := app.GenerateClientSecret()
    82  	assert.NoError(t, err)
    83  	assert.True(t, app.ValidateClientSecret([]byte(secret)))
    84  	assert.False(t, app.ValidateClientSecret([]byte("fewijfowejgfiowjeoifew")))
    85  }
    86  
    87  func TestGetOAuth2ApplicationByClientID(t *testing.T) {
    88  	assert.NoError(t, unittest.PrepareTestDatabase())
    89  	app, err := auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138")
    90  	assert.NoError(t, err)
    91  	assert.Equal(t, "da7da3ba-9a13-4167-856f-3899de0b0138", app.ClientID)
    92  
    93  	app, err = auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id")
    94  	assert.Error(t, err)
    95  	assert.Nil(t, app)
    96  }
    97  
    98  func TestCreateOAuth2Application(t *testing.T) {
    99  	assert.NoError(t, unittest.PrepareTestDatabase())
   100  	app, err := auth_model.CreateOAuth2Application(db.DefaultContext, auth_model.CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1})
   101  	assert.NoError(t, err)
   102  	assert.Equal(t, "newapp", app.Name)
   103  	assert.Len(t, app.ClientID, 36)
   104  	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{Name: "newapp"})
   105  }
   106  
   107  func TestOAuth2Application_TableName(t *testing.T) {
   108  	assert.Equal(t, "oauth2_application", new(auth_model.OAuth2Application).TableName())
   109  }
   110  
   111  func TestOAuth2Application_GetGrantByUserID(t *testing.T) {
   112  	assert.NoError(t, unittest.PrepareTestDatabase())
   113  	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
   114  	grant, err := app.GetGrantByUserID(db.DefaultContext, 1)
   115  	assert.NoError(t, err)
   116  	assert.Equal(t, int64(1), grant.UserID)
   117  
   118  	grant, err = app.GetGrantByUserID(db.DefaultContext, 34923458)
   119  	assert.NoError(t, err)
   120  	assert.Nil(t, grant)
   121  }
   122  
   123  func TestOAuth2Application_CreateGrant(t *testing.T) {
   124  	assert.NoError(t, unittest.PrepareTestDatabase())
   125  	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
   126  	grant, err := app.CreateGrant(db.DefaultContext, 2, "")
   127  	assert.NoError(t, err)
   128  	assert.NotNil(t, grant)
   129  	assert.Equal(t, int64(2), grant.UserID)
   130  	assert.Equal(t, int64(1), grant.ApplicationID)
   131  	assert.Equal(t, "", grant.Scope)
   132  }
   133  
   134  //////////////////// Grant
   135  
   136  func TestGetOAuth2GrantByID(t *testing.T) {
   137  	assert.NoError(t, unittest.PrepareTestDatabase())
   138  	grant, err := auth_model.GetOAuth2GrantByID(db.DefaultContext, 1)
   139  	assert.NoError(t, err)
   140  	assert.Equal(t, int64(1), grant.ID)
   141  
   142  	grant, err = auth_model.GetOAuth2GrantByID(db.DefaultContext, 34923458)
   143  	assert.NoError(t, err)
   144  	assert.Nil(t, grant)
   145  }
   146  
   147  func TestOAuth2Grant_IncreaseCounter(t *testing.T) {
   148  	assert.NoError(t, unittest.PrepareTestDatabase())
   149  	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 1})
   150  	assert.NoError(t, grant.IncreaseCounter(db.DefaultContext))
   151  	assert.Equal(t, int64(2), grant.Counter)
   152  	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 2})
   153  }
   154  
   155  func TestOAuth2Grant_ScopeContains(t *testing.T) {
   156  	assert.NoError(t, unittest.PrepareTestDatabase())
   157  	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Scope: "openid profile"})
   158  	assert.True(t, grant.ScopeContains("openid"))
   159  	assert.True(t, grant.ScopeContains("profile"))
   160  	assert.False(t, grant.ScopeContains("profil"))
   161  	assert.False(t, grant.ScopeContains("profile2"))
   162  }
   163  
   164  func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) {
   165  	assert.NoError(t, unittest.PrepareTestDatabase())
   166  	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
   167  	code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256")
   168  	assert.NoError(t, err)
   169  	assert.NotNil(t, code)
   170  	assert.True(t, len(code.Code) > 32) // secret length > 32
   171  }
   172  
   173  func TestOAuth2Grant_TableName(t *testing.T) {
   174  	assert.Equal(t, "oauth2_grant", new(auth_model.OAuth2Grant).TableName())
   175  }
   176  
   177  func TestGetOAuth2GrantsByUserID(t *testing.T) {
   178  	assert.NoError(t, unittest.PrepareTestDatabase())
   179  	result, err := auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 1)
   180  	assert.NoError(t, err)
   181  	assert.Len(t, result, 1)
   182  	assert.Equal(t, int64(1), result[0].ID)
   183  	assert.Equal(t, result[0].ApplicationID, result[0].Application.ID)
   184  
   185  	result, err = auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 34134)
   186  	assert.NoError(t, err)
   187  	assert.Empty(t, result)
   188  }
   189  
   190  func TestRevokeOAuth2Grant(t *testing.T) {
   191  	assert.NoError(t, unittest.PrepareTestDatabase())
   192  	assert.NoError(t, auth_model.RevokeOAuth2Grant(db.DefaultContext, 1, 1))
   193  	unittest.AssertNotExistsBean(t, &auth_model.OAuth2Grant{ID: 1, UserID: 1})
   194  }
   195  
   196  //////////////////// Authorization Code
   197  
   198  func TestGetOAuth2AuthorizationByCode(t *testing.T) {
   199  	assert.NoError(t, unittest.PrepareTestDatabase())
   200  	code, err := auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode")
   201  	assert.NoError(t, err)
   202  	assert.NotNil(t, code)
   203  	assert.Equal(t, "authcode", code.Code)
   204  	assert.Equal(t, int64(1), code.ID)
   205  
   206  	code, err = auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist")
   207  	assert.NoError(t, err)
   208  	assert.Nil(t, code)
   209  }
   210  
   211  func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
   212  	// test plain
   213  	code := &auth_model.OAuth2AuthorizationCode{
   214  		CodeChallengeMethod: "plain",
   215  		CodeChallenge:       "test123",
   216  	}
   217  	assert.True(t, code.ValidateCodeChallenge("test123"))
   218  	assert.False(t, code.ValidateCodeChallenge("ierwgjoergjio"))
   219  
   220  	// test S256
   221  	code = &auth_model.OAuth2AuthorizationCode{
   222  		CodeChallengeMethod: "S256",
   223  		CodeChallenge:       "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg",
   224  	}
   225  	assert.True(t, code.ValidateCodeChallenge("N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt"))
   226  	assert.False(t, code.ValidateCodeChallenge("wiogjerogorewngoenrgoiuenorg"))
   227  
   228  	// test unknown
   229  	code = &auth_model.OAuth2AuthorizationCode{
   230  		CodeChallengeMethod: "monkey",
   231  		CodeChallenge:       "foiwgjioriogeiogjerger",
   232  	}
   233  	assert.False(t, code.ValidateCodeChallenge("foiwgjioriogeiogjerger"))
   234  
   235  	// test no code challenge
   236  	code = &auth_model.OAuth2AuthorizationCode{
   237  		CodeChallengeMethod: "",
   238  		CodeChallenge:       "foierjiogerogerg",
   239  	}
   240  	assert.True(t, code.ValidateCodeChallenge(""))
   241  }
   242  
   243  func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
   244  	code := &auth_model.OAuth2AuthorizationCode{
   245  		RedirectURI: "https://example.com/callback",
   246  		Code:        "thecode",
   247  	}
   248  
   249  	redirect, err := code.GenerateRedirectURI("thestate")
   250  	assert.NoError(t, err)
   251  	assert.Equal(t, "https://example.com/callback?code=thecode&state=thestate", redirect.String())
   252  
   253  	redirect, err = code.GenerateRedirectURI("")
   254  	assert.NoError(t, err)
   255  	assert.Equal(t, "https://example.com/callback?code=thecode", redirect.String())
   256  }
   257  
   258  func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) {
   259  	assert.NoError(t, unittest.PrepareTestDatabase())
   260  	code := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
   261  	assert.NoError(t, code.Invalidate(db.DefaultContext))
   262  	unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
   263  }
   264  
   265  func TestOAuth2AuthorizationCode_TableName(t *testing.T) {
   266  	assert.Equal(t, "oauth2_authorization_code", new(auth_model.OAuth2AuthorizationCode).TableName())
   267  }