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