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 }