[MISC] Implement golint recommendations (#885)
Co-authored-by: Clément Michaud <clement.michaud34@gmail.com>pull/822/head
parent
a6b7a8632b
commit
2e784084c7
|
@ -1,4 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
// BuildTag tag used to bootstrap Authelia binary.
|
||||||
var BuildTag = "__BUILD_TAG__"
|
var BuildTag = "__BUILD_TAG__"
|
||||||
|
|
||||||
|
// BuildCommit commit used to bootstrap Authelia binary.
|
||||||
var BuildCommit = "__BUILD_COMMIT__"
|
var BuildCommit = "__BUILD_COMMIT__"
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -19,7 +19,7 @@ require (
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kr/pty v1.1.8 // indirect
|
github.com/kr/pty v1.1.8 // indirect
|
||||||
github.com/lib/pq v1.3.0
|
github.com/lib/pq v1.3.0
|
||||||
github.com/mattn/go-sqlite3 v1.13.0
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||||
github.com/ogier/pflag v0.0.1 // indirect
|
github.com/ogier/pflag v0.0.1 // indirect
|
||||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||||
github.com/onsi/gomega v1.7.1 // indirect
|
github.com/onsi/gomega v1.7.1 // indirect
|
||||||
|
@ -32,7 +32,7 @@ require (
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
github.com/tebeka/selenium v0.9.9
|
github.com/tebeka/selenium v0.9.9
|
||||||
github.com/tstranex/u2f v1.0.0
|
github.com/tstranex/u2f v1.0.0
|
||||||
github.com/valyala/fasthttp v1.10.0
|
github.com/valyala/fasthttp v1.11.0
|
||||||
github.com/xdg/stringprep v1.0.0 // indirect
|
github.com/xdg/stringprep v1.0.0 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.3.2
|
go.mongodb.org/mongo-driver v1.3.2
|
||||||
google.golang.org/appengine v1.6.5 // indirect
|
google.golang.org/appengine v1.6.5 // indirect
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -89,6 +89,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
|
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
|
||||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
|
github.com/go-redis/redis/v7 v7.2.0 h1:CrCexy/jYWZjW0AyVoHlcJUeZN19VWlbepTh1Vq6dJs=
|
||||||
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
|
@ -212,6 +213,7 @@ github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A
|
||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||||
github.com/mattn/go-sqlite3 v1.13.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.13.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
@ -447,6 +449,7 @@ golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
package authentication
|
package authentication
|
||||||
|
|
||||||
// Level is the type representing a level of authentication
|
// Level is the type representing a level of authentication.
|
||||||
type Level int
|
type Level int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// NotAuthenticated if the user is not authenticated yet
|
// NotAuthenticated if the user is not authenticated yet.
|
||||||
NotAuthenticated Level = iota
|
NotAuthenticated Level = iota
|
||||||
// OneFactor if the user has passed first factor only
|
// OneFactor if the user has passed first factor only.
|
||||||
OneFactor Level = iota
|
OneFactor Level = iota
|
||||||
// TwoFactor if the user has passed two factors
|
// TwoFactor if the user has passed two factors.
|
||||||
TwoFactor Level = iota
|
TwoFactor Level = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TOTP Method using Time-Based One-Time Password applications like Google Authenticator
|
// TOTP Method using Time-Based One-Time Password applications like Google Authenticator.
|
||||||
TOTP = "totp"
|
TOTP = "totp"
|
||||||
// U2F Method using U2F devices like Yubikeys
|
// U2F Method using U2F devices like Yubikeys.
|
||||||
U2F = "u2f"
|
U2F = "u2f"
|
||||||
// Push Method using Duo application to receive push notifications
|
// Push Method using Duo application to receive push notifications.
|
||||||
Push = "mobile_push"
|
Push = "mobile_push"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,13 +25,14 @@ const (
|
||||||
var PossibleMethods = []string{TOTP, U2F, Push}
|
var PossibleMethods = []string{TOTP, U2F, Push}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//Argon2id Hash Identifier
|
// HashingAlgorithmArgon2id Argon2id hash identifier.
|
||||||
HashingAlgorithmArgon2id = "argon2id"
|
HashingAlgorithmArgon2id = "argon2id"
|
||||||
//SHA512 Hash Identifier
|
// HashingAlgorithmSHA512 SHA512 hash identifier.
|
||||||
HashingAlgorithmSHA512 = "6"
|
HashingAlgorithmSHA512 = "6"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are the default values from the upstream crypt module, we use them to for GetInt, and they need to be checked when updating github.com/simia-tech/crypt
|
// These are the default values from the upstream crypt module we use them to for GetInt
|
||||||
|
// and they need to be checked when updating github.com/simia-tech/crypt.
|
||||||
const (
|
const (
|
||||||
HashingDefaultArgon2idTime = 1
|
HashingDefaultArgon2idTime = 1
|
||||||
HashingDefaultArgon2idMemory = 32 * 1024
|
HashingDefaultArgon2idMemory = 32 * 1024
|
||||||
|
@ -40,5 +41,5 @@ const (
|
||||||
HashingDefaultSHA512Iterations = 5000
|
HashingDefaultSHA512Iterations = 5000
|
||||||
)
|
)
|
||||||
|
|
||||||
// HashingPossibleSaltCharacters represents valid hashing runes
|
// HashingPossibleSaltCharacters represents valid hashing runes.
|
||||||
var HashingPossibleSaltCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/")
|
var HashingPossibleSaltCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/")
|
||||||
|
|
|
@ -17,35 +17,39 @@ type LDAPConnection interface {
|
||||||
Modify(modifyRequest *ldap.ModifyRequest) error
|
Modify(modifyRequest *ldap.ModifyRequest) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAPConnectionImpl the production implementation of an ldap connection
|
// LDAPConnectionImpl the production implementation of an ldap connection.
|
||||||
type LDAPConnectionImpl struct {
|
type LDAPConnectionImpl struct {
|
||||||
conn *ldap.Conn
|
conn *ldap.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLDAPConnectionImpl create a new ldap connection
|
// NewLDAPConnectionImpl create a new ldap connection.
|
||||||
func NewLDAPConnectionImpl(conn *ldap.Conn) *LDAPConnectionImpl {
|
func NewLDAPConnectionImpl(conn *ldap.Conn) *LDAPConnectionImpl {
|
||||||
return &LDAPConnectionImpl{conn}
|
return &LDAPConnectionImpl{conn}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bind binds ldap connection to a username/password.
|
||||||
func (lc *LDAPConnectionImpl) Bind(username, password string) error {
|
func (lc *LDAPConnectionImpl) Bind(username, password string) error {
|
||||||
return lc.conn.Bind(username, password)
|
return lc.conn.Bind(username, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close closes a ldap connection.
|
||||||
func (lc *LDAPConnectionImpl) Close() {
|
func (lc *LDAPConnectionImpl) Close() {
|
||||||
lc.conn.Close()
|
lc.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search searches a ldap server.
|
||||||
func (lc *LDAPConnectionImpl) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) {
|
func (lc *LDAPConnectionImpl) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) {
|
||||||
return lc.conn.Search(searchRequest)
|
return lc.conn.Search(searchRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modify modifies an ldap object.
|
||||||
func (lc *LDAPConnectionImpl) Modify(modifyRequest *ldap.ModifyRequest) error {
|
func (lc *LDAPConnectionImpl) Modify(modifyRequest *ldap.ModifyRequest) error {
|
||||||
return lc.conn.Modify(modifyRequest)
|
return lc.conn.Modify(modifyRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ********************* FACTORY ***********************
|
// ********************* FACTORY ***********************
|
||||||
|
|
||||||
// LDAPConnectionFactory an interface of factory of ldap connections
|
// LDAPConnectionFactory an interface of factory of ldap connections.
|
||||||
type LDAPConnectionFactory interface {
|
type LDAPConnectionFactory interface {
|
||||||
DialTLS(network, addr string, config *tls.Config) (LDAPConnection, error)
|
DialTLS(network, addr string, config *tls.Config) (LDAPConnection, error)
|
||||||
Dial(network, addr string) (LDAPConnection, error)
|
Dial(network, addr string) (LDAPConnection, error)
|
||||||
|
@ -54,7 +58,7 @@ type LDAPConnectionFactory interface {
|
||||||
// LDAPConnectionFactoryImpl the production implementation of an ldap connection factory.
|
// LDAPConnectionFactoryImpl the production implementation of an ldap connection factory.
|
||||||
type LDAPConnectionFactoryImpl struct{}
|
type LDAPConnectionFactoryImpl struct{}
|
||||||
|
|
||||||
// NewLDAPConnectionFactoryImpl create a concrete ldap connection factory
|
// NewLDAPConnectionFactoryImpl create a concrete ldap connection factory.
|
||||||
func NewLDAPConnectionFactoryImpl() *LDAPConnectionFactoryImpl {
|
func NewLDAPConnectionFactoryImpl() *LDAPConnectionFactoryImpl {
|
||||||
return &LDAPConnectionFactoryImpl{}
|
return &LDAPConnectionFactoryImpl{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ func NewLDAPUserProvider(configuration schema.LDAPAuthenticationBackendConfigura
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewLDAPUserProviderWithFactory creates a new instance of LDAPUserProvider with existing factory.
|
||||||
func NewLDAPUserProviderWithFactory(configuration schema.LDAPAuthenticationBackendConfiguration,
|
func NewLDAPUserProviderWithFactory(configuration schema.LDAPAuthenticationBackendConfiguration,
|
||||||
connectionFactory LDAPConnectionFactory) *LDAPUserProvider {
|
connectionFactory LDAPConnectionFactory) *LDAPUserProvider {
|
||||||
return &LDAPUserProvider{
|
return &LDAPUserProvider{
|
||||||
|
@ -90,7 +91,7 @@ func (p *LDAPUserProvider) CheckUserPassword(inputUsername string, password stri
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OWASP recommends to escape some special characters
|
// OWASP recommends to escape some special characters.
|
||||||
// https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.md
|
// https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.md
|
||||||
const specialLDAPRunes = ",#+<>;\"="
|
const specialLDAPRunes = ",#+<>;\"="
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ type ldapUserProfile struct {
|
||||||
func (p *LDAPUserProvider) resolveUsersFilter(userFilter string, inputUsername string) string {
|
func (p *LDAPUserProvider) resolveUsersFilter(userFilter string, inputUsername string) string {
|
||||||
inputUsername = p.ldapEscape(inputUsername)
|
inputUsername = p.ldapEscape(inputUsername)
|
||||||
|
|
||||||
// We temporarily keep placeholder {0} for backward compatibility
|
// We temporarily keep placeholder {0} for backward compatibility.
|
||||||
userFilter = strings.ReplaceAll(userFilter, "{0}", inputUsername)
|
userFilter = strings.ReplaceAll(userFilter, "{0}", inputUsername)
|
||||||
|
|
||||||
// The {username} placeholder is equivalent to {0}, it's the new way, a named placeholder.
|
// The {username} placeholder is equivalent to {0}, it's the new way, a named placeholder.
|
||||||
|
@ -137,7 +138,7 @@ func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername str
|
||||||
p.configuration.MailAttribute,
|
p.configuration.MailAttribute,
|
||||||
p.configuration.UsernameAttribute}
|
p.configuration.UsernameAttribute}
|
||||||
|
|
||||||
// Search for the given username
|
// Search for the given username.
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||||
1, 0, false, userFilter, attributes, nil,
|
1, 0, false, userFilter, attributes, nil,
|
||||||
|
@ -182,11 +183,11 @@ func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername str
|
||||||
func (p *LDAPUserProvider) resolveGroupsFilter(inputUsername string, profile *ldapUserProfile) (string, error) { //nolint:unparam
|
func (p *LDAPUserProvider) resolveGroupsFilter(inputUsername string, profile *ldapUserProfile) (string, error) { //nolint:unparam
|
||||||
inputUsername = p.ldapEscape(inputUsername)
|
inputUsername = p.ldapEscape(inputUsername)
|
||||||
|
|
||||||
// We temporarily keep placeholder {0} for backward compatibility
|
// We temporarily keep placeholder {0} for backward compatibility.
|
||||||
groupFilter := strings.ReplaceAll(p.configuration.GroupsFilter, "{0}", inputUsername)
|
groupFilter := strings.ReplaceAll(p.configuration.GroupsFilter, "{0}", inputUsername)
|
||||||
groupFilter = strings.ReplaceAll(groupFilter, "{input}", inputUsername)
|
groupFilter = strings.ReplaceAll(groupFilter, "{input}", inputUsername)
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
// We temporarily keep placeholder {1} for backward compatibility
|
// We temporarily keep placeholder {1} for backward compatibility.
|
||||||
groupFilter = strings.ReplaceAll(groupFilter, "{1}", ldap.EscapeFilter(profile.Username))
|
groupFilter = strings.ReplaceAll(groupFilter, "{1}", ldap.EscapeFilter(profile.Username))
|
||||||
groupFilter = strings.ReplaceAll(groupFilter, "{username}", ldap.EscapeFilter(profile.Username))
|
groupFilter = strings.ReplaceAll(groupFilter, "{username}", ldap.EscapeFilter(profile.Username))
|
||||||
groupFilter = strings.ReplaceAll(groupFilter, "{dn}", ldap.EscapeFilter(profile.DN))
|
groupFilter = strings.ReplaceAll(groupFilter, "{dn}", ldap.EscapeFilter(profile.DN))
|
||||||
|
@ -219,7 +220,7 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
|
||||||
groupBaseDN = p.configuration.AdditionalGroupsDN + "," + groupBaseDN
|
groupBaseDN = p.configuration.AdditionalGroupsDN + "," + groupBaseDN
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for the given username
|
// Search for the given username.
|
||||||
searchGroupRequest := ldap.NewSearchRequest(
|
searchGroupRequest := ldap.NewSearchRequest(
|
||||||
groupBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
groupBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||||
0, 0, false, groupsFilter, []string{p.configuration.GroupNameAttribute}, nil,
|
0, 0, false, groupsFilter, []string{p.configuration.GroupNameAttribute}, nil,
|
||||||
|
@ -237,7 +238,7 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
|
||||||
logging.Logger().Warningf("No groups retrieved from LDAP for user %s", inputUsername)
|
logging.Logger().Warningf("No groups retrieved from LDAP for user %s", inputUsername)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// append all values of the document. Normally there should be only one per document.
|
// Append all values of the document. Normally there should be only one per document.
|
||||||
groups = append(groups, res.Attributes[0].Values...)
|
groups = append(groups, res.Attributes[0].Values...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ func selectMatchingRules(rules []schema.ACLRule, subject Subject, object Object)
|
||||||
return selectMatchingObjectRules(matchingRules, object)
|
return selectMatchingObjectRules(matchingRules, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PolicyToLevel converts a string policy to int authorization level.
|
||||||
func PolicyToLevel(policy string) Level {
|
func PolicyToLevel(policy string) Level {
|
||||||
switch policy {
|
switch policy {
|
||||||
case "bypass":
|
case "bypass":
|
||||||
|
|
|
@ -171,11 +171,13 @@ func generateSelfSignedCertificate(cmd *cobra.Command, args []string) {
|
||||||
log.Printf("wrote %s\n", keyPath)
|
log.Printf("wrote %s\n", keyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CertificatesCmd certificate helper command.
|
||||||
var CertificatesCmd = &cobra.Command{
|
var CertificatesCmd = &cobra.Command{
|
||||||
Use: "certificates",
|
Use: "certificates",
|
||||||
Short: "Commands related to certificate generation",
|
Short: "Commands related to certificate generation",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CertificatesGenerateCmd certificate generation command.
|
||||||
var CertificatesGenerateCmd = &cobra.Command{
|
var CertificatesGenerateCmd = &cobra.Command{
|
||||||
Use: "generate",
|
Use: "generate",
|
||||||
Short: "Generate a self-signed certificate",
|
Short: "Generate a self-signed certificate",
|
||||||
|
|
|
@ -19,6 +19,7 @@ func init() {
|
||||||
HashPasswordCmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordConfiguration.SaltLength, "set the auto-generated salt length")
|
HashPasswordCmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordConfiguration.SaltLength, "set the auto-generated salt length")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashPasswordCmd password hashing command.
|
||||||
var HashPasswordCmd = &cobra.Command{
|
var HashPasswordCmd = &cobra.Command{
|
||||||
Use: "hash-password [password]",
|
Use: "hash-password [password]",
|
||||||
Short: "Hash a password to be used in file-based users database. Default algorithm is argon2id.",
|
Short: "Hash a password to be used in file-based users database. Default algorithm is argon2id.",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/authelia/authelia/internal/storage"
|
"github.com/authelia/authelia/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MigrateCmd migration helper command.
|
||||||
var MigrateCmd *cobra.Command
|
var MigrateCmd *cobra.Command
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -20,7 +21,7 @@ func init() {
|
||||||
MigrateCmd.AddCommand(MigrateLocalCmd, MigrateMongoCmd)
|
MigrateCmd.AddCommand(MigrateLocalCmd, MigrateMongoCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOTPSecretsV3 one entry of TOTP secrets in v3
|
// TOTPSecretsV3 one entry of TOTP secrets in v3.
|
||||||
type TOTPSecretsV3 struct {
|
type TOTPSecretsV3 struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Secret struct {
|
Secret struct {
|
||||||
|
@ -28,7 +29,7 @@ type TOTPSecretsV3 struct {
|
||||||
} `json:"secret"`
|
} `json:"secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// U2FDeviceHandleV3 one entry of U2F device handle in v3
|
// U2FDeviceHandleV3 one entry of U2F device handle in v3.
|
||||||
type U2FDeviceHandleV3 struct {
|
type U2FDeviceHandleV3 struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Registration struct {
|
Registration struct {
|
||||||
|
@ -37,13 +38,13 @@ type U2FDeviceHandleV3 struct {
|
||||||
} `json:"registration"`
|
} `json:"registration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreferencesV3 one entry of preferences in v3
|
// PreferencesV3 one entry of preferences in v3.
|
||||||
type PreferencesV3 struct {
|
type PreferencesV3 struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthenticationTraceV3 one authentication trace in v3
|
// AuthenticationTraceV3 one authentication trace in v3.
|
||||||
type AuthenticationTraceV3 struct {
|
type AuthenticationTraceV3 struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Successful bool `json:"isAuthenticationSuccessful"`
|
Successful bool `json:"isAuthenticationSuccessful"`
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
var configurationPath string
|
var configurationPath string
|
||||||
var localDatabasePath string
|
var localDatabasePath string
|
||||||
|
|
||||||
// MigrateLocalCmd migration command
|
// MigrateLocalCmd migration command.
|
||||||
var MigrateLocalCmd = &cobra.Command{
|
var MigrateLocalCmd = &cobra.Command{
|
||||||
Use: "localdb",
|
Use: "localdb",
|
||||||
Short: "Migrate data from v3 local database into database configured in v4 configuration file",
|
Short: "Migrate data from v3 local database into database configured in v4 configuration file",
|
||||||
|
@ -32,7 +32,7 @@ func init() {
|
||||||
MigrateLocalCmd.MarkPersistentFlagRequired("config")
|
MigrateLocalCmd.MarkPersistentFlagRequired("config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrateLocal data from v3 to v4
|
// migrateLocal data from v3 to v4.
|
||||||
func migrateLocal(cmd *cobra.Command, args []string) {
|
func migrateLocal(cmd *cobra.Command, args []string) {
|
||||||
dbProvider := createDBProvider(configurationPath)
|
dbProvider := createDBProvider(configurationPath)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
var mongoURL string
|
var mongoURL string
|
||||||
var mongoDatabase string
|
var mongoDatabase string
|
||||||
|
|
||||||
// MigrateMongoCmd migration command
|
// MigrateMongoCmd migration command.
|
||||||
var MigrateMongoCmd = &cobra.Command{
|
var MigrateMongoCmd = &cobra.Command{
|
||||||
Use: "mongo",
|
Use: "mongo",
|
||||||
Short: "Migrate data from v3 mongo database into database configured in v4 configuration file",
|
Short: "Migrate data from v3 mongo database into database configured in v4 configuration file",
|
||||||
|
|
|
@ -6,8 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ACLRule represent one ACL rule
|
// ACLRule represent one ACL rule "weak" coerces a single value into string slice.
|
||||||
// "weak" coerces a single value into string slice
|
|
||||||
type ACLRule struct {
|
type ACLRule struct {
|
||||||
Domains []string `mapstructure:"domain,weak"`
|
Domains []string `mapstructure:"domain,weak"`
|
||||||
Policy string `mapstructure:"policy"`
|
Policy string `mapstructure:"policy"`
|
||||||
|
@ -16,25 +15,24 @@ type ACLRule struct {
|
||||||
Resources []string `mapstructure:"resources"`
|
Resources []string `mapstructure:"resources"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPolicyValid check if policy is valid
|
// IsPolicyValid check if policy is valid.
|
||||||
func IsPolicyValid(policy string) bool {
|
func IsPolicyValid(policy string) bool {
|
||||||
return policy == "deny" || policy == "one_factor" || policy == "two_factor" || policy == "bypass"
|
return policy == "deny" || policy == "one_factor" || policy == "two_factor" || policy == "bypass"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSubjectValid check if a subject is valid
|
// IsSubjectValid check if a subject is valid.
|
||||||
func IsSubjectValid(subject string) bool {
|
func IsSubjectValid(subject string) bool {
|
||||||
return subject == "" || strings.HasPrefix(subject, "user:") || strings.HasPrefix(subject, "group:")
|
return subject == "" || strings.HasPrefix(subject, "user:") || strings.HasPrefix(subject, "group:")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNetworkValid check if a network is valid
|
// IsNetworkValid check if a network is valid.
|
||||||
func IsNetworkValid(network string) bool {
|
func IsNetworkValid(network string) bool {
|
||||||
_, _, err := net.ParseCIDR(network)
|
_, _, err := net.ParseCIDR(network)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validate an ACL Rule
|
// Validate validate an ACL Rule.
|
||||||
func (r *ACLRule) Validate(validator *StructValidator) {
|
func (r *ACLRule) Validate(validator *StructValidator) {
|
||||||
|
|
||||||
if len(r.Domains) == 0 {
|
if len(r.Domains) == 0 {
|
||||||
validator.Push(fmt.Errorf("Domain must be provided"))
|
validator.Push(fmt.Errorf("Domain must be provided"))
|
||||||
}
|
}
|
||||||
|
@ -62,7 +60,7 @@ type AccessControlConfiguration struct {
|
||||||
Rules []ACLRule `mapstructure:"rules"`
|
Rules []ACLRule `mapstructure:"rules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validate the access control configuration
|
// Validate validate the access control configuration.
|
||||||
func (acc *AccessControlConfiguration) Validate(validator *StructValidator) {
|
func (acc *AccessControlConfiguration) Validate(validator *StructValidator) {
|
||||||
if acc.DefaultPolicy == "" {
|
if acc.DefaultPolicy == "" {
|
||||||
acc.DefaultPolicy = "deny"
|
acc.DefaultPolicy = "deny"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
// LDAPAuthenticationBackendConfiguration represents the configuration related to LDAP server
|
// LDAPAuthenticationBackendConfiguration represents the configuration related to LDAP server.
|
||||||
type LDAPAuthenticationBackendConfiguration struct {
|
type LDAPAuthenticationBackendConfiguration struct {
|
||||||
URL string `mapstructure:"url"`
|
URL string `mapstructure:"url"`
|
||||||
SkipVerify bool `mapstructure:"skip_verify"`
|
SkipVerify bool `mapstructure:"skip_verify"`
|
||||||
|
@ -16,12 +16,13 @@ type LDAPAuthenticationBackendConfiguration struct {
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileAuthenticationBackendConfiguration represents the configuration related to file-based backend
|
// FileAuthenticationBackendConfiguration represents the configuration related to file-based backend.
|
||||||
type FileAuthenticationBackendConfiguration struct {
|
type FileAuthenticationBackendConfiguration struct {
|
||||||
Path string `mapstructure:"path"`
|
Path string `mapstructure:"path"`
|
||||||
Password *PasswordConfiguration `mapstructure:"password"`
|
Password *PasswordConfiguration `mapstructure:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PasswordConfiguration represents the configuration related to password hashing.
|
||||||
type PasswordConfiguration struct {
|
type PasswordConfiguration struct {
|
||||||
Iterations int `mapstructure:"iterations"`
|
Iterations int `mapstructure:"iterations"`
|
||||||
KeyLength int `mapstructure:"key_length"`
|
KeyLength int `mapstructure:"key_length"`
|
||||||
|
@ -31,7 +32,7 @@ type PasswordConfiguration struct {
|
||||||
Parallelism int `mapstructure:"parallelism"`
|
Parallelism int `mapstructure:"parallelism"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultPasswordConfiguration represents the default configuration related to Argon2id hashing
|
// DefaultPasswordConfiguration represents the default configuration related to Argon2id hashing.
|
||||||
var DefaultPasswordConfiguration = PasswordConfiguration{
|
var DefaultPasswordConfiguration = PasswordConfiguration{
|
||||||
Iterations: 1,
|
Iterations: 1,
|
||||||
KeyLength: 32,
|
KeyLength: 32,
|
||||||
|
@ -41,7 +42,7 @@ var DefaultPasswordConfiguration = PasswordConfiguration{
|
||||||
Parallelism: 8,
|
Parallelism: 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultCIPasswordConfiguration represents the default configuration related to Argon2id hashing for CI
|
// DefaultCIPasswordConfiguration represents the default configuration related to Argon2id hashing for CI.
|
||||||
var DefaultCIPasswordConfiguration = PasswordConfiguration{
|
var DefaultCIPasswordConfiguration = PasswordConfiguration{
|
||||||
Iterations: 1,
|
Iterations: 1,
|
||||||
KeyLength: 32,
|
KeyLength: 32,
|
||||||
|
@ -51,14 +52,14 @@ var DefaultCIPasswordConfiguration = PasswordConfiguration{
|
||||||
Parallelism: 8,
|
Parallelism: 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultPasswordSHA512Configuration represents the default configuration related to SHA512 hashing
|
// DefaultPasswordSHA512Configuration represents the default configuration related to SHA512 hashing.
|
||||||
var DefaultPasswordSHA512Configuration = PasswordConfiguration{
|
var DefaultPasswordSHA512Configuration = PasswordConfiguration{
|
||||||
Iterations: 50000,
|
Iterations: 50000,
|
||||||
SaltLength: 16,
|
SaltLength: 16,
|
||||||
Algorithm: "sha512",
|
Algorithm: "sha512",
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthenticationBackendConfiguration represents the configuration related to the authentication backend
|
// AuthenticationBackendConfiguration represents the configuration related to the authentication backend.
|
||||||
type AuthenticationBackendConfiguration struct {
|
type AuthenticationBackendConfiguration struct {
|
||||||
DisableResetPassword bool `mapstructure:"disable_reset_password"`
|
DisableResetPassword bool `mapstructure:"disable_reset_password"`
|
||||||
Ldap *LDAPAuthenticationBackendConfiguration `mapstructure:"ldap"`
|
Ldap *LDAPAuthenticationBackendConfiguration `mapstructure:"ldap"`
|
||||||
|
|
|
@ -24,6 +24,7 @@ type NotifierConfiguration struct {
|
||||||
SMTP *SMTPNotifierConfiguration `mapstructure:"smtp"`
|
SMTP *SMTPNotifierConfiguration `mapstructure:"smtp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultSMTPNotifierConfiguration represents default configuration parameters for the SMTP notifier.
|
||||||
var DefaultSMTPNotifierConfiguration = SMTPNotifierConfiguration{
|
var DefaultSMTPNotifierConfiguration = SMTPNotifierConfiguration{
|
||||||
Subject: "[Authelia] {title}",
|
Subject: "[Authelia] {title}",
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ type RegulationConfiguration struct {
|
||||||
BanTime string `mapstructure:"ban_time"`
|
BanTime string `mapstructure:"ban_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultRegulationConfiguration represents default configuration parameters for the regulator.
|
||||||
var DefaultRegulationConfiguration = RegulationConfiguration{
|
var DefaultRegulationConfiguration = RegulationConfiguration{
|
||||||
MaxRetries: 3,
|
MaxRetries: 3,
|
||||||
FindTime: "2m",
|
FindTime: "2m",
|
||||||
|
|
|
@ -8,6 +8,8 @@ type TOTPConfiguration struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultOtpSkew = 1
|
var defaultOtpSkew = 1
|
||||||
|
|
||||||
|
// DefaultTOTPConfiguration represents default configuration parameters for TOTP generation.
|
||||||
var DefaultTOTPConfiguration = TOTPConfiguration{
|
var DefaultTOTPConfiguration = TOTPConfiguration{
|
||||||
Issuer: "Authelia",
|
Issuer: "Authelia",
|
||||||
Period: 30,
|
Period: 30,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/authelia/authelia/internal/configuration/schema"
|
"github.com/authelia/authelia/internal/configuration/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateSession validates and update session configuration.
|
// ValidateNotifier validates and update notifier configuration.
|
||||||
func ValidateNotifier(configuration *schema.NotifierConfiguration, validator *schema.StructValidator) {
|
func ValidateNotifier(configuration *schema.NotifierConfiguration, validator *schema.StructValidator) {
|
||||||
if configuration.SMTP == nil && configuration.FileSystem == nil {
|
if configuration.SMTP == nil && configuration.FileSystem == nil {
|
||||||
validator.Push(fmt.Errorf("Notifier should be either `smtp` or `filesystem`"))
|
validator.Push(fmt.Errorf("Notifier should be either `smtp` or `filesystem`"))
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/authelia/authelia/internal/utils"
|
"github.com/authelia/authelia/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateSession validates and update session configuration.
|
// ValidateRegulation validates and update regulator configuration.
|
||||||
func ValidateRegulation(configuration *schema.RegulationConfiguration, validator *schema.StructValidator) {
|
func ValidateRegulation(configuration *schema.RegulationConfiguration, validator *schema.StructValidator) {
|
||||||
if configuration.FindTime == "" {
|
if configuration.FindTime == "" {
|
||||||
configuration.FindTime = schema.DefaultRegulationConfiguration.FindTime // 2 min
|
configuration.FindTime = schema.DefaultRegulationConfiguration.FindTime // 2 min
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/authelia/authelia/internal/configuration/schema"
|
"github.com/authelia/authelia/internal/configuration/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateSQLStorage validates storage configuration.
|
// ValidateStorage validates storage configuration.
|
||||||
func ValidateStorage(configuration schema.StorageConfiguration, validator *schema.StructValidator) {
|
func ValidateStorage(configuration schema.StorageConfiguration, validator *schema.StructValidator) {
|
||||||
if configuration.Local == nil && configuration.MySQL == nil && configuration.PostgreSQL == nil {
|
if configuration.Local == nil && configuration.MySQL == nil && configuration.PostgreSQL == nil {
|
||||||
validator.Push(errors.New("A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'"))
|
validator.Push(errors.New("A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'"))
|
||||||
|
|
|
@ -11,6 +11,7 @@ const ResetPasswordAction = "ResetPassword"
|
||||||
|
|
||||||
const authPrefix = "Basic "
|
const authPrefix = "Basic "
|
||||||
|
|
||||||
|
// AuthorizationHeader is the basic-auth HTTP header Authelia utilises.
|
||||||
const AuthorizationHeader = "Proxy-Authorization"
|
const AuthorizationHeader = "Proxy-Authorization"
|
||||||
const remoteUserHeader = "Remote-User"
|
const remoteUserHeader = "Remote-User"
|
||||||
const remoteGroupsHeader = "Remote-Groups"
|
const remoteGroupsHeader = "Remote-Groups"
|
||||||
|
@ -18,7 +19,7 @@ const remoteGroupsHeader = "Remote-Groups"
|
||||||
var protoHostSeparator = []byte("://")
|
var protoHostSeparator = []byte("://")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Forbidden means the user is forbidden the access to a resource
|
// Forbidden means the user is forbidden the access to a resource.
|
||||||
Forbidden authorizationMatching = iota
|
Forbidden authorizationMatching = iota
|
||||||
// NotAuthorized means the user can access the resource with more permissions.
|
// NotAuthorized means the user can access the resource with more permissions.
|
||||||
NotAuthorized authorizationMatching = iota
|
NotAuthorized authorizationMatching = iota
|
||||||
|
|
|
@ -2,12 +2,14 @@ package handlers
|
||||||
|
|
||||||
import "github.com/authelia/authelia/internal/middlewares"
|
import "github.com/authelia/authelia/internal/middlewares"
|
||||||
|
|
||||||
|
// ConfigurationBody configuration parameters exposed to the frontend.
|
||||||
type ConfigurationBody struct {
|
type ConfigurationBody struct {
|
||||||
GoogleAnalyticsTrackingID string `json:"ga_tracking_id,omitempty"`
|
GoogleAnalyticsTrackingID string `json:"ga_tracking_id,omitempty"`
|
||||||
RememberMe bool `json:"remember_me"` // whether remember me is enabled or not
|
RememberMe bool `json:"remember_me"` // whether remember me is enabled or not
|
||||||
ResetPassword bool `json:"reset_password"`
|
ResetPassword bool `json:"reset_password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigurationGet fetches configuration parameters for frontend mutation.
|
||||||
func ConfigurationGet(ctx *middlewares.AutheliaCtx) {
|
func ConfigurationGet(ctx *middlewares.AutheliaCtx) {
|
||||||
body := ConfigurationBody{
|
body := ConfigurationBody{
|
||||||
GoogleAnalyticsTrackingID: ctx.Configuration.GoogleAnalyticsTrackingID,
|
GoogleAnalyticsTrackingID: ctx.Configuration.GoogleAnalyticsTrackingID,
|
||||||
|
|
|
@ -79,6 +79,7 @@ func UserInfoGet(ctx *middlewares.AutheliaCtx) {
|
||||||
ctx.SetJSONBody(preferences)
|
ctx.SetJSONBody(preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MethodBody the selected 2FA method.
|
||||||
type MethodBody struct {
|
type MethodBody struct {
|
||||||
Method string `json:"method" valid:"required"`
|
Method string `json:"method" valid:"required"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,18 @@ import (
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TOTPVerifier is the interface for verifying TOTPs.
|
||||||
type TOTPVerifier interface {
|
type TOTPVerifier interface {
|
||||||
Verify(token, secret string) (bool, error)
|
Verify(token, secret string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TOTPVerifierImpl the production implementation for TOTP verification.
|
||||||
type TOTPVerifierImpl struct {
|
type TOTPVerifierImpl struct {
|
||||||
Period uint
|
Period uint
|
||||||
Skew uint
|
Skew uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify verifies TOTPs.
|
||||||
func (tv *TOTPVerifierImpl) Verify(token, secret string) (bool, error) {
|
func (tv *TOTPVerifierImpl) Verify(token, secret string) (bool, error) {
|
||||||
opts := totp.ValidateOpts{
|
opts := totp.ValidateOpts{
|
||||||
Period: tv.Period,
|
Period: tv.Period,
|
||||||
|
|
|
@ -11,15 +11,15 @@ type MethodList = []string
|
||||||
|
|
||||||
type authorizationMatching int
|
type authorizationMatching int
|
||||||
|
|
||||||
// UserInfo is the model of user second factor preferences
|
// UserInfo is the model of user second factor preferences.
|
||||||
type UserPreferences struct {
|
type UserPreferences struct {
|
||||||
// The preferred 2FA method.
|
// The preferred 2FA method.
|
||||||
Method string `json:"method" valid:"required"`
|
Method string `json:"method" valid:"required"`
|
||||||
|
|
||||||
// True if a security key has been registered
|
// True if a security key has been registered.
|
||||||
HasU2F bool `json:"has_u2f" valid:"required"`
|
HasU2F bool `json:"has_u2f" valid:"required"`
|
||||||
|
|
||||||
// True if a TOTP device has been registered
|
// True if a TOTP device has been registered.
|
||||||
HasTOTP bool `json:"has_totp" valid:"required"`
|
HasTOTP bool `json:"has_totp" valid:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,12 +68,12 @@ type StateResponse struct {
|
||||||
DefaultRedirectionURL string `json:"default_redirection_url"`
|
DefaultRedirectionURL string `json:"default_redirection_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetPasswordStep1RequestBody model of the reset password (step1) request body
|
// resetPasswordStep1RequestBody model of the reset password (step1) request body.
|
||||||
type resetPasswordStep1RequestBody struct {
|
type resetPasswordStep1RequestBody struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetPasswordStep2RequestBody model of the reset password (step2) request body
|
// resetPasswordStep2RequestBody model of the reset password (step2) request body.
|
||||||
type resetPasswordStep2RequestBody struct {
|
type resetPasswordStep2RequestBody struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,15 @@ import (
|
||||||
"github.com/tstranex/u2f"
|
"github.com/tstranex/u2f"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// U2FVerifier is the interface for verifying U2F keys.
|
||||||
type U2FVerifier interface {
|
type U2FVerifier interface {
|
||||||
Verify(keyHandle []byte, publicKey []byte, signResponse u2f.SignResponse, challenge u2f.Challenge) error
|
Verify(keyHandle []byte, publicKey []byte, signResponse u2f.SignResponse, challenge u2f.Challenge) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// U2FVerifierImpl the production implementation for U2F key verification.
|
||||||
type U2FVerifierImpl struct{}
|
type U2FVerifierImpl struct{}
|
||||||
|
|
||||||
|
// Verify verifies U2F keys.
|
||||||
func (uv *U2FVerifierImpl) Verify(keyHandle []byte, publicKey []byte,
|
func (uv *U2FVerifierImpl) Verify(keyHandle []byte, publicKey []byte,
|
||||||
signResponse u2f.SignResponse, challenge u2f.Challenge) error {
|
signResponse u2f.SignResponse, challenge u2f.Challenge) error {
|
||||||
var registration u2f.Registration
|
var registration u2f.Registration
|
||||||
|
|
|
@ -23,14 +23,14 @@ import (
|
||||||
"github.com/authelia/authelia/internal/session"
|
"github.com/authelia/authelia/internal/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockAutheliaCtx a mock of AutheliaCtx
|
// MockAutheliaCtx a mock of AutheliaCtx.
|
||||||
type MockAutheliaCtx struct {
|
type MockAutheliaCtx struct {
|
||||||
// Logger hook
|
// Logger hook.
|
||||||
Hook *test.Hook
|
Hook *test.Hook
|
||||||
Ctx *middlewares.AutheliaCtx
|
Ctx *middlewares.AutheliaCtx
|
||||||
Ctrl *gomock.Controller
|
Ctrl *gomock.Controller
|
||||||
|
|
||||||
// Providers
|
// Providers.
|
||||||
UserProviderMock *MockUserProvider
|
UserProviderMock *MockUserProvider
|
||||||
StorageProviderMock *storage.MockProvider
|
StorageProviderMock *storage.MockProvider
|
||||||
NotifierMock *MockNotifier
|
NotifierMock *MockNotifier
|
||||||
|
@ -40,27 +40,27 @@ type MockAutheliaCtx struct {
|
||||||
Clock TestingClock
|
Clock TestingClock
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestingClock implementation of clock for tests
|
// TestingClock implementation of clock for tests.
|
||||||
type TestingClock struct {
|
type TestingClock struct {
|
||||||
now time.Time
|
now time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now return the stored clock
|
// Now return the stored clock.
|
||||||
func (dc *TestingClock) Now() time.Time {
|
func (dc *TestingClock) Now() time.Time {
|
||||||
return dc.now
|
return dc.now
|
||||||
}
|
}
|
||||||
|
|
||||||
// After return a channel receiving the time after duration has elapsed
|
// After return a channel receiving the time after duration has elapsed.
|
||||||
func (dc *TestingClock) After(d time.Duration) <-chan time.Time {
|
func (dc *TestingClock) After(d time.Duration) <-chan time.Time {
|
||||||
return time.After(d)
|
return time.After(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set set the time of the clock
|
// Set set the time of the clock.
|
||||||
func (dc *TestingClock) Set(now time.Time) {
|
func (dc *TestingClock) Set(now time.Time) {
|
||||||
dc.now = now
|
dc.now = now
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMockAutheliaCtx create an instance of AutheliaCtx mock
|
// NewMockAutheliaCtx create an instance of AutheliaCtx mock.
|
||||||
func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
|
func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
|
||||||
mockAuthelia := new(MockAutheliaCtx)
|
mockAuthelia := new(MockAutheliaCtx)
|
||||||
mockAuthelia.Clock = TestingClock{}
|
mockAuthelia.Clock = TestingClock{}
|
||||||
|
@ -107,7 +107,7 @@ func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
|
||||||
providers.Regulator = regulation.NewRegulator(configuration.Regulation, providers.StorageProvider, &mockAuthelia.Clock)
|
providers.Regulator = regulation.NewRegulator(configuration.Regulation, providers.StorageProvider, &mockAuthelia.Clock)
|
||||||
|
|
||||||
request := &fasthttp.RequestCtx{}
|
request := &fasthttp.RequestCtx{}
|
||||||
// Set a cookie to identify this client throughout the test
|
// Set a cookie to identify this client throughout the test.
|
||||||
// request.Request.Header.SetCookie("authelia_session", "client_cookie")
|
// request.Request.Header.SetCookie("authelia_session", "client_cookie")
|
||||||
|
|
||||||
autheliaCtx, _ := middlewares.NewAutheliaCtx(request, configuration, providers)
|
autheliaCtx, _ := middlewares.NewAutheliaCtx(request, configuration, providers)
|
||||||
|
@ -120,7 +120,7 @@ func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
|
||||||
return mockAuthelia
|
return mockAuthelia
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close close the mock
|
// Close close the mock.
|
||||||
func (m *MockAutheliaCtx) Close() {
|
func (m *MockAutheliaCtx) Close() {
|
||||||
m.Hook.Reset()
|
m.Hook.Reset()
|
||||||
m.Ctrl.Finish()
|
m.Ctrl.Finish()
|
||||||
|
@ -146,6 +146,7 @@ func (m *MockAutheliaCtx) Assert200OK(t *testing.T, data interface{}) {
|
||||||
assert.Equal(t, string(b), string(m.Ctx.Response.Body()))
|
assert.Equal(t, string(b), string(m.Ctx.Response.Body()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResponseData retrieves a response from the service.
|
||||||
func (m *MockAutheliaCtx) GetResponseData(t *testing.T, data interface{}) {
|
func (m *MockAutheliaCtx) GetResponseData(t *testing.T, data interface{}) {
|
||||||
okResponse := middlewares.OKResponse{}
|
okResponse := middlewares.OKResponse{}
|
||||||
okResponse.Data = data
|
okResponse.Data = data
|
||||||
|
|
|
@ -2,7 +2,7 @@ package models
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Attempt represent an authentication attempt.
|
// AuthenticationAttempt represent an authentication attempt.
|
||||||
type AuthenticationAttempt struct {
|
type AuthenticationAttempt struct {
|
||||||
// The user who tried to authenticate.
|
// The user who tried to authenticate.
|
||||||
Username string
|
Username string
|
||||||
|
|
|
@ -6,12 +6,21 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrTimeoutReached error thrown when a timeout is reached
|
// ErrTimeoutReached error thrown when a timeout is reached.
|
||||||
var ErrTimeoutReached = errors.New("timeout reached")
|
var ErrTimeoutReached = errors.New("timeout reached")
|
||||||
var parseDurationRegexp = regexp.MustCompile(`^(?P<Duration>[1-9]\d*?)(?P<Unit>[smhdwMy])?$`)
|
var parseDurationRegexp = regexp.MustCompile(`^(?P<Duration>[1-9]\d*?)(?P<Unit>[smhdwMy])?$`)
|
||||||
|
|
||||||
|
// Hour is an int based representation of the time unit
|
||||||
const Hour = time.Minute * 60
|
const Hour = time.Minute * 60
|
||||||
|
|
||||||
|
// Day is an int based representation of the time unit
|
||||||
const Day = Hour * 24
|
const Day = Hour * 24
|
||||||
|
|
||||||
|
// Week is an int based representation of the time unit
|
||||||
const Week = Day * 7
|
const Week = Day * 7
|
||||||
|
|
||||||
|
// Year is an int based representation of the time unit
|
||||||
const Year = Day * 365
|
const Year = Day * 365
|
||||||
|
|
||||||
|
// Month is an int based representation of the time unit
|
||||||
const Month = Year / 12
|
const Month = Year / 12
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IsRedirectionSafe determines if a redirection URL is secured.
|
||||||
func IsRedirectionSafe(url url.URL, protectedDomain string) bool {
|
func IsRedirectionSafe(url url.URL, protectedDomain string) bool {
|
||||||
if url.Scheme != "https" {
|
if url.Scheme != "https" {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checks if a single string is in an array of strings
|
// IsStringInSlice checks if a single string is in an array of strings.
|
||||||
func IsStringInSlice(a string, list []string) (inSlice bool) {
|
func IsStringInSlice(a string, list []string) (inSlice bool) {
|
||||||
for _, b := range list {
|
for _, b := range list {
|
||||||
if b == a {
|
if b == a {
|
||||||
|
@ -15,8 +15,8 @@ func IsStringInSlice(a string, list []string) (inSlice bool) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits a string s into an array with each item being a max of int d
|
// SliceString splits a string s into an array with each item being a max of int d
|
||||||
// d = denominator, n = numerator, q = quotient, r = remainder
|
// d = denominator, n = numerator, q = quotient, r = remainder.
|
||||||
func SliceString(s string, d int) (array []string) {
|
func SliceString(s string, d int) (array []string) {
|
||||||
n := len(s)
|
n := len(s)
|
||||||
q := n / d
|
q := n / d
|
||||||
|
@ -30,7 +30,7 @@ func SliceString(s string, d int) (array []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomString generate a random string of n characters
|
// RandomString generate a random string of n characters.
|
||||||
func RandomString(n int, characters []rune) (randomString string) {
|
func RandomString(n int, characters []rune) (randomString string) {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
b := make([]rune, n)
|
b := make([]rune, n)
|
||||||
|
|
Loading…
Reference in New Issue