Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
id
auth
Commits
da156e68
Commit
da156e68
authored
Nov 18, 2020
by
ale
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow primary-password login for users that have ASPs on other services
parent
e1eb24cc
Pipeline
#8726
passed with stages
in 1 minute and 46 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
29 additions
and
22 deletions
+29
-22
backend/backend.go
backend/backend.go
+9
-4
server/authserver.go
server/authserver.go
+15
-14
server/authserver_test.go
server/authserver_test.go
+4
-4
server/sql_test.go
server/sql_test.go
+1
-0
No files found.
backend/backend.go
View file @
da156e68
...
...
@@ -29,14 +29,19 @@ type AppSpecificPassword struct {
EncryptedPassword
[]
byte
}
// Has2FA returns true if the user supports any 2FA method.
// Has2FA returns true if the user supports any
interactive
2FA method.
func
(
u
*
User
)
Has2FA
()
bool
{
return
u
.
HasU2F
()
||
u
.
HasOTP
()
||
u
.
HasASPs
()
return
u
.
HasU2F
()
||
u
.
HasOTP
()
}
// HasASPs returns true if the user has app-specific passwords.
func
(
u
*
User
)
HasASPs
()
bool
{
return
len
(
u
.
AppSpecificPasswords
)
>
0
func
(
u
*
User
)
HasASPs
(
service
string
)
bool
{
for
_
,
asp
:=
range
u
.
AppSpecificPasswords
{
if
asp
.
Service
==
service
{
return
true
}
}
return
false
}
// HasOTP returns true if the user supports (T)OTP.
...
...
server/authserver.go
View file @
da156e68
...
...
@@ -386,35 +386,36 @@ fail:
// Authenticate a user. Returning an error should result in an
// AuthResponse with StatusError.
func
(
s
*
Server
)
authenticateUser
(
req
*
auth
.
Request
,
svc
*
service
,
user
*
backend
.
User
)
(
resp
*
auth
.
Response
,
err
error
)
{
err
=
errNoMechanisms
// The service can override the ASP service name presented in
// the request.
aspService
:=
req
.
Service
if
svc
.
aspService
!=
""
{
aspService
=
svc
.
aspService
}
// Verify different credentials depending on whether the user
// has 2FA enabled or not, and on whether the service itself
// supports challenge-response authentication.
err
=
errNoMechanisms
if
svc
.
ignore2FA
{
resp
,
err
=
s
.
authenticateUserWithPassword
(
user
,
req
)
}
else
if
svc
.
challengeResponse
{
if
svc
.
enforce2FA
||
user
.
Has2FA
()
{
resp
,
err
=
s
.
authenticateUserWith2FA
(
user
,
req
)
}
else
if
user
.
HasASPs
()
{
}
else
if
user
.
HasASPs
(
aspService
)
{
// It doesn't make much sense to support ASPs
// for a challenge-response service, but we
// still do it for completeness.
//
// Rewrite the 'service' for app-specific
// password matching, if necessary.
if
svc
.
aspService
!=
""
{
req
.
Service
=
svc
.
aspService
}
resp
,
err
=
s
.
authenticateUserWithASP
(
user
,
req
)
resp
,
err
=
s
.
authenticateUserWithASP
(
user
,
req
,
aspService
)
}
else
{
resp
,
err
=
s
.
authenticateUserWithPassword
(
user
,
req
)
}
}
else
if
svc
.
enforce2FA
||
user
.
HasASPs
()
{
if
svc
.
aspService
!=
""
{
req
.
Service
=
svc
.
aspService
}
resp
,
err
=
s
.
authenticateUserWithASP
(
user
,
req
)
}
else
if
svc
.
enforce2FA
||
user
.
HasASPs
(
aspService
)
{
resp
,
err
=
s
.
authenticateUserWithASP
(
user
,
req
,
aspService
)
}
else
if
!
user
.
Has2FA
()
{
resp
,
err
=
s
.
authenticateUserWithPassword
(
user
,
req
)
}
...
...
@@ -452,9 +453,9 @@ func (s *Server) authenticateUserWithPassword(user *backend.User, req *auth.Requ
return
nil
,
errBadPassword
}
func
(
s
*
Server
)
authenticateUserWithASP
(
user
*
backend
.
User
,
req
*
auth
.
Request
)
(
*
auth
.
Response
,
error
)
{
func
(
s
*
Server
)
authenticateUserWithASP
(
user
*
backend
.
User
,
req
*
auth
.
Request
,
aspService
string
)
(
*
auth
.
Response
,
error
)
{
for
_
,
asp
:=
range
user
.
AppSpecificPasswords
{
if
asp
.
Service
==
req
.
Service
&&
checkPassword
(
req
.
Password
,
asp
.
EncryptedPassword
)
{
if
asp
.
Service
==
asp
Service
&&
checkPassword
(
req
.
Password
,
asp
.
EncryptedPassword
)
{
return
newOK
(),
nil
}
}
...
...
server/authserver_test.go
View file @
da156e68
...
...
@@ -151,9 +151,9 @@ func runBackendTest(t *testing.T, srv *Server) {
expectGroups
[]
string
expectHasOTP
,
expectHasU2F
,
expectHasASPs
bool
}{
{
"testuser"
,
"
interactive
"
,
nil
,
false
,
false
,
false
},
{
"2fauser"
,
"
interactive
"
,
nil
,
true
,
true
,
false
},
{
"aspuser"
,
"
interactive
"
,
nil
,
false
,
false
,
true
},
{
"testuser"
,
"
test
"
,
nil
,
false
,
false
,
false
},
{
"2fauser"
,
"
test
"
,
nil
,
true
,
true
,
false
},
{
"aspuser"
,
"
test
"
,
nil
,
false
,
false
,
true
},
}
for
_
,
td
:=
range
testdata
{
svc
,
ok
:=
srv
.
getService
(
td
.
service
)
...
...
@@ -172,7 +172,7 @@ func runBackendTest(t *testing.T, srv *Server) {
if
b
:=
user
.
HasU2F
();
b
!=
td
.
expectHasU2F
{
t
.
Errorf
(
"user %s has_u2f=%v, expected=%v"
,
td
.
username
,
b
,
td
.
expectHasU2F
)
}
if
b
:=
user
.
HasASPs
();
b
!=
td
.
expectHasASPs
{
if
b
:=
user
.
HasASPs
(
td
.
service
);
b
!=
td
.
expectHasASPs
{
t
.
Errorf
(
"user %s has_asp=%v, expected=%v"
,
td
.
username
,
b
,
td
.
expectHasASPs
)
}
}
...
...
server/sql_test.go
View file @
da156e68
...
...
@@ -38,6 +38,7 @@ services:
params:
queries:
get_user: "SELECT email, password, totp_secret, '' AS shard FROM users WHERE name = ?"
get_user_u2f: "SELECT public_key, key_handle FROM u2f_registrations WHERE name = ?"
get_user_asp: "SELECT service, password FROM asps WHERE name = ?"
no2fa:
ignore_2fa: true
...
...
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