Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
e4cfcae6
Commit
e4cfcae6
authored
Apr 21, 2026
by
IanShaw027
Browse files
fix: reassign oauth adoption decisions on repeat login
parent
11db3989
Changes
2
Hide whitespace changes
Inline
Side-by-side
backend/internal/handler/auth_oauth_pending_flow.go
View file @
e4cfcae6
...
@@ -1107,6 +1107,15 @@ func applyPendingOAuthBindingTx(
...
@@ -1107,6 +1107,15 @@ func applyPendingOAuthBindingTx(
}
}
if
decision
!=
nil
&&
(
decision
.
IdentityID
==
nil
||
*
decision
.
IdentityID
!=
identity
.
ID
)
{
if
decision
!=
nil
&&
(
decision
.
IdentityID
==
nil
||
*
decision
.
IdentityID
!=
identity
.
ID
)
{
if
_
,
err
:=
tx
.
Client
()
.
IdentityAdoptionDecision
.
Update
()
.
Where
(
identityadoptiondecision
.
IdentityIDEQ
(
identity
.
ID
),
identityadoptiondecision
.
IDNEQ
(
decision
.
ID
),
)
.
ClearIdentityID
()
.
Save
(
ctx
);
err
!=
nil
{
return
err
}
if
_
,
err
:=
tx
.
Client
()
.
IdentityAdoptionDecision
.
UpdateOneID
(
decision
.
ID
)
.
if
_
,
err
:=
tx
.
Client
()
.
IdentityAdoptionDecision
.
UpdateOneID
(
decision
.
ID
)
.
SetIdentityID
(
identity
.
ID
)
.
SetIdentityID
(
identity
.
ID
)
.
Save
(
ctx
);
err
!=
nil
{
Save
(
ctx
);
err
!=
nil
{
...
...
backend/internal/handler/auth_oauth_pending_flow_test.go
View file @
e4cfcae6
...
@@ -537,6 +537,114 @@ func TestExchangePendingOAuthCompletionLoginFalseFalseBindsIdentityWithoutAdopti
...
@@ -537,6 +537,114 @@ func TestExchangePendingOAuthCompletionLoginFalseFalseBindsIdentityWithoutAdopti
require
.
NotNil
(
t
,
storedSession
.
ConsumedAt
)
require
.
NotNil
(
t
,
storedSession
.
ConsumedAt
)
}
}
func
TestExchangePendingOAuthCompletionLoginReassignsExistingDecisionIdentityReference
(
t
*
testing
.
T
)
{
handler
,
client
:=
newOAuthPendingFlowTestHandler
(
t
,
false
)
ctx
:=
context
.
Background
()
userEntity
,
err
:=
client
.
User
.
Create
()
.
SetEmail
(
"login-reassign@example.com"
)
.
SetUsername
(
"legacy-name"
)
.
SetPasswordHash
(
"hash"
)
.
SetRole
(
service
.
RoleUser
)
.
SetStatus
(
service
.
StatusActive
)
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
existingIdentity
,
err
:=
client
.
AuthIdentity
.
Create
()
.
SetUserID
(
userEntity
.
ID
)
.
SetProviderType
(
"linuxdo"
)
.
SetProviderKey
(
"linuxdo"
)
.
SetProviderSubject
(
"login-reassign-123"
)
.
SetMetadata
(
map
[
string
]
any
{})
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
previousSession
,
err
:=
client
.
PendingAuthSession
.
Create
()
.
SetSessionToken
(
"login-reassign-previous-session-token"
)
.
SetIntent
(
"login"
)
.
SetProviderType
(
"linuxdo"
)
.
SetProviderKey
(
"linuxdo"
)
.
SetProviderSubject
(
"login-reassign-123"
)
.
SetTargetUserID
(
userEntity
.
ID
)
.
SetResolvedEmail
(
userEntity
.
Email
)
.
SetBrowserSessionKey
(
"login-reassign-previous-browser-session-key"
)
.
SetLocalFlowState
(
map
[
string
]
any
{
oauthCompletionResponseKey
:
map
[
string
]
any
{
"access_token"
:
"previous-access-token"
,
},
})
.
SetExpiresAt
(
time
.
Now
()
.
UTC
()
.
Add
(
10
*
time
.
Minute
))
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
previousDecision
,
err
:=
client
.
IdentityAdoptionDecision
.
Create
()
.
SetPendingAuthSessionID
(
previousSession
.
ID
)
.
SetIdentityID
(
existingIdentity
.
ID
)
.
SetAdoptDisplayName
(
true
)
.
SetAdoptAvatar
(
true
)
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
session
,
err
:=
client
.
PendingAuthSession
.
Create
()
.
SetSessionToken
(
"login-reassign-session-token"
)
.
SetIntent
(
"login"
)
.
SetProviderType
(
"linuxdo"
)
.
SetProviderKey
(
"linuxdo"
)
.
SetProviderSubject
(
"login-reassign-123"
)
.
SetTargetUserID
(
userEntity
.
ID
)
.
SetResolvedEmail
(
userEntity
.
Email
)
.
SetBrowserSessionKey
(
"login-reassign-browser-session-key"
)
.
SetUpstreamIdentityClaims
(
map
[
string
]
any
{
"suggested_display_name"
:
"Login Reassign"
,
"suggested_avatar_url"
:
"https://cdn.example/login-reassign.png"
,
})
.
SetLocalFlowState
(
map
[
string
]
any
{
oauthCompletionResponseKey
:
map
[
string
]
any
{
"access_token"
:
"access-token"
,
},
})
.
SetExpiresAt
(
time
.
Now
()
.
UTC
()
.
Add
(
10
*
time
.
Minute
))
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
_
,
err
=
client
.
IdentityAdoptionDecision
.
Create
()
.
SetPendingAuthSessionID
(
session
.
ID
)
.
SetAdoptDisplayName
(
false
)
.
SetAdoptAvatar
(
false
)
.
Save
(
ctx
)
require
.
NoError
(
t
,
err
)
body
:=
bytes
.
NewBufferString
(
`{"adopt_display_name":false,"adopt_avatar":false}`
)
recorder
:=
httptest
.
NewRecorder
()
ginCtx
,
_
:=
gin
.
CreateTestContext
(
recorder
)
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/api/v1/auth/oauth/pending/exchange"
,
body
)
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
req
.
AddCookie
(
&
http
.
Cookie
{
Name
:
oauthPendingSessionCookieName
,
Value
:
encodeCookieValue
(
session
.
SessionToken
)})
req
.
AddCookie
(
&
http
.
Cookie
{
Name
:
oauthPendingBrowserCookieName
,
Value
:
encodeCookieValue
(
"login-reassign-browser-session-key"
)})
ginCtx
.
Request
=
req
handler
.
ExchangePendingOAuthCompletion
(
ginCtx
)
require
.
Equal
(
t
,
http
.
StatusOK
,
recorder
.
Code
)
reloadedPrevious
,
err
:=
client
.
IdentityAdoptionDecision
.
Get
(
ctx
,
previousDecision
.
ID
)
require
.
NoError
(
t
,
err
)
require
.
Nil
(
t
,
reloadedPrevious
.
IdentityID
)
currentDecision
,
err
:=
client
.
IdentityAdoptionDecision
.
Query
()
.
Where
(
identityadoptiondecision
.
PendingAuthSessionIDEQ
(
session
.
ID
))
.
Only
(
ctx
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
currentDecision
.
IdentityID
)
require
.
Equal
(
t
,
existingIdentity
.
ID
,
*
currentDecision
.
IdentityID
)
storedSession
,
err
:=
client
.
PendingAuthSession
.
Query
()
.
Where
(
pendingauthsession
.
IDEQ
(
session
.
ID
))
.
Only
(
ctx
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
storedSession
.
ConsumedAt
)
}
func
TestExchangePendingOAuthCompletionLoginWithoutDecisionStillBindsIdentity
(
t
*
testing
.
T
)
{
func
TestExchangePendingOAuthCompletionLoginWithoutDecisionStillBindsIdentity
(
t
*
testing
.
T
)
{
handler
,
client
:=
newOAuthPendingFlowTestHandler
(
t
,
false
)
handler
,
client
:=
newOAuthPendingFlowTestHandler
(
t
,
false
)
ctx
:=
context
.
Background
()
ctx
:=
context
.
Background
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment