diff --git a/README.md b/README.md index 8a040cf55..bc5fd5f6f 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ This is a list of the key features of Authelia: * Several second factor methods: * **[Security Keys](https://www.authelia.com/overview/authentication/security-key/)** that support - [FIDO2] [Webauthn] with devices like a [YubiKey]. + [FIDO2] [WebAuthn] with devices like a [YubiKey]. * **[Time-based One-Time password](https://www.authelia.com/overview/authentication/one-time-password/)** with compatible authenticator applications. * **[Mobile Push Notifications](https://www.authelia.com/overview/authentication/push-notification/)** @@ -399,7 +399,7 @@ Companies contributing to Authelia via Open Collective will have a special menti [TOTP]: https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm [FIDO2]: https://www.yubico.com/authentication-standards/fido2/ [YubiKey]: https://www.yubico.com/products/yubikey-5-overview/ -[Webauthn]: https://www.yubico.com/authentication-standards/webauthn/ +[WebAuthn]: https://www.yubico.com/authentication-standards/webauthn/ [auth_request]: https://nginx.org/en/docs/http/ngx_http_auth_request_module.html [config.template.yml]: ./config.template.yml [nginx]: https://www.authelia.com/integration/proxies/nginx/ diff --git a/docs/content/en/configuration/identity-providers/open-id-connect.md b/docs/content/en/configuration/identity-providers/open-id-connect.md index 40b3bd695..a01f33f3c 100644 --- a/docs/content/en/configuration/identity-providers/open-id-connect.md +++ b/docs/content/en/configuration/identity-providers/open-id-connect.md @@ -548,8 +548,8 @@ more information. {{< confkey type="string" default="auto" required="no" >}} *__Important Note:__ the `implicit` consent mode is not technically part of the specification. It theoretically could be -misused in certain conditions specifically with public clients or when the client credentials (i.e. client secret) has -been exposed to an attacker. For these reasons this mode is discouraged.* +misused in certain conditions specifically with the public client type or when the client credentials (i.e. client +secret) has been exposed to an attacker. For these reasons this mode is discouraged.* Configures the consent mode. The following table describes the different modes: diff --git a/docs/content/en/contributing/development/environment.md b/docs/content/en/contributing/development/environment.md index 008b87fc5..356ea2e42 100644 --- a/docs/content/en/contributing/development/environment.md +++ b/docs/content/en/contributing/development/environment.md @@ -23,6 +23,7 @@ In order to build and contribute to __Authelia__, you need to make sure the foll * Backend Development: * [go] *(v1.20 or greater)* * [gcc] + * [gomock] * Frontend Development * [Node.js] *(v18 or greater)* * [pnpm] @@ -95,6 +96,7 @@ listed subdomains from your browser, and they will be served by the reverse prox [Buildkite]: https://buildkite.com/ [React]: https://reactjs.org/ [go]: https://go.dev/dl/ +[gomock]: https://github.com/golang/mock [Node.js]: https://nodejs.org/en/download/ [pnpm]: https://pnpm.io/installation [Docker]: https://docs.docker.com/get-docker/ diff --git a/internal/authentication/ldap_client_mock.go b/internal/authentication/ldap_client_mock.go index dfeb4389f..c58b602a2 100644 --- a/internal/authentication/ldap_client_mock.go +++ b/internal/authentication/ldap_client_mock.go @@ -7,6 +7,7 @@ package authentication import ( tls "crypto/tls" reflect "reflect" + time "time" ldap "github.com/go-ldap/ldap/v3" gomock "github.com/golang/mock/gomock" @@ -35,6 +36,20 @@ func (m *MockLDAPClient) EXPECT() *MockLDAPClientMockRecorder { return m.recorder } +// Add mocks base method. +func (m *MockLDAPClient) Add(arg0 *ldap.AddRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Add", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Add indicates an expected call of Add. +func (mr *MockLDAPClientMockRecorder) Add(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockLDAPClient)(nil).Add), arg0) +} + // Bind mocks base method. func (m *MockLDAPClient) Bind(arg0, arg1 string) error { m.ctrl.T.Helper() @@ -61,6 +76,92 @@ func (mr *MockLDAPClientMockRecorder) Close() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockLDAPClient)(nil).Close)) } +// Compare mocks base method. +func (m *MockLDAPClient) Compare(arg0, arg1, arg2 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Compare", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Compare indicates an expected call of Compare. +func (mr *MockLDAPClientMockRecorder) Compare(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compare", reflect.TypeOf((*MockLDAPClient)(nil).Compare), arg0, arg1, arg2) +} + +// Del mocks base method. +func (m *MockLDAPClient) Del(arg0 *ldap.DelRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Del", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Del indicates an expected call of Del. +func (mr *MockLDAPClientMockRecorder) Del(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockLDAPClient)(nil).Del), arg0) +} + +// DigestMD5Bind mocks base method. +func (m *MockLDAPClient) DigestMD5Bind(arg0 *ldap.DigestMD5BindRequest) (*ldap.DigestMD5BindResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DigestMD5Bind", arg0) + ret0, _ := ret[0].(*ldap.DigestMD5BindResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DigestMD5Bind indicates an expected call of DigestMD5Bind. +func (mr *MockLDAPClientMockRecorder) DigestMD5Bind(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DigestMD5Bind", reflect.TypeOf((*MockLDAPClient)(nil).DigestMD5Bind), arg0) +} + +// ExternalBind mocks base method. +func (m *MockLDAPClient) ExternalBind() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExternalBind") + ret0, _ := ret[0].(error) + return ret0 +} + +// ExternalBind indicates an expected call of ExternalBind. +func (mr *MockLDAPClientMockRecorder) ExternalBind() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExternalBind", reflect.TypeOf((*MockLDAPClient)(nil).ExternalBind)) +} + +// IsClosing mocks base method. +func (m *MockLDAPClient) IsClosing() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsClosing") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsClosing indicates an expected call of IsClosing. +func (mr *MockLDAPClientMockRecorder) IsClosing() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsClosing", reflect.TypeOf((*MockLDAPClient)(nil).IsClosing)) +} + +// MD5Bind mocks base method. +func (m *MockLDAPClient) MD5Bind(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MD5Bind", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// MD5Bind indicates an expected call of MD5Bind. +func (mr *MockLDAPClientMockRecorder) MD5Bind(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MD5Bind", reflect.TypeOf((*MockLDAPClient)(nil).MD5Bind), arg0, arg1, arg2) +} + // Modify mocks base method. func (m *MockLDAPClient) Modify(arg0 *ldap.ModifyRequest) error { m.ctrl.T.Helper() @@ -75,6 +176,92 @@ func (mr *MockLDAPClientMockRecorder) Modify(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockLDAPClient)(nil).Modify), arg0) } +// ModifyDN mocks base method. +func (m *MockLDAPClient) ModifyDN(arg0 *ldap.ModifyDNRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModifyDN", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// ModifyDN indicates an expected call of ModifyDN. +func (mr *MockLDAPClientMockRecorder) ModifyDN(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDN", reflect.TypeOf((*MockLDAPClient)(nil).ModifyDN), arg0) +} + +// ModifyWithResult mocks base method. +func (m *MockLDAPClient) ModifyWithResult(arg0 *ldap.ModifyRequest) (*ldap.ModifyResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModifyWithResult", arg0) + ret0, _ := ret[0].(*ldap.ModifyResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ModifyWithResult indicates an expected call of ModifyWithResult. +func (mr *MockLDAPClientMockRecorder) ModifyWithResult(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyWithResult", reflect.TypeOf((*MockLDAPClient)(nil).ModifyWithResult), arg0) +} + +// NTLMBind mocks base method. +func (m *MockLDAPClient) NTLMBind(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NTLMBind", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// NTLMBind indicates an expected call of NTLMBind. +func (mr *MockLDAPClientMockRecorder) NTLMBind(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMBind", reflect.TypeOf((*MockLDAPClient)(nil).NTLMBind), arg0, arg1, arg2) +} + +// NTLMBindWithHash mocks base method. +func (m *MockLDAPClient) NTLMBindWithHash(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NTLMBindWithHash", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// NTLMBindWithHash indicates an expected call of NTLMBindWithHash. +func (mr *MockLDAPClientMockRecorder) NTLMBindWithHash(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMBindWithHash", reflect.TypeOf((*MockLDAPClient)(nil).NTLMBindWithHash), arg0, arg1, arg2) +} + +// NTLMChallengeBind mocks base method. +func (m *MockLDAPClient) NTLMChallengeBind(arg0 *ldap.NTLMBindRequest) (*ldap.NTLMBindResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NTLMChallengeBind", arg0) + ret0, _ := ret[0].(*ldap.NTLMBindResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NTLMChallengeBind indicates an expected call of NTLMChallengeBind. +func (mr *MockLDAPClientMockRecorder) NTLMChallengeBind(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMChallengeBind", reflect.TypeOf((*MockLDAPClient)(nil).NTLMChallengeBind), arg0) +} + +// NTLMUnauthenticatedBind mocks base method. +func (m *MockLDAPClient) NTLMUnauthenticatedBind(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NTLMUnauthenticatedBind", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// NTLMUnauthenticatedBind indicates an expected call of NTLMUnauthenticatedBind. +func (mr *MockLDAPClientMockRecorder) NTLMUnauthenticatedBind(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMUnauthenticatedBind", reflect.TypeOf((*MockLDAPClient)(nil).NTLMUnauthenticatedBind), arg0, arg1) +} + // PasswordModify mocks base method. func (m *MockLDAPClient) PasswordModify(arg0 *ldap.PasswordModifyRequest) (*ldap.PasswordModifyResult, error) { m.ctrl.T.Helper() @@ -105,6 +292,60 @@ func (mr *MockLDAPClientMockRecorder) Search(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Search", reflect.TypeOf((*MockLDAPClient)(nil).Search), arg0) } +// SearchWithPaging mocks base method. +func (m *MockLDAPClient) SearchWithPaging(arg0 *ldap.SearchRequest, arg1 uint32) (*ldap.SearchResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchWithPaging", arg0, arg1) + ret0, _ := ret[0].(*ldap.SearchResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchWithPaging indicates an expected call of SearchWithPaging. +func (mr *MockLDAPClientMockRecorder) SearchWithPaging(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchWithPaging", reflect.TypeOf((*MockLDAPClient)(nil).SearchWithPaging), arg0, arg1) +} + +// SetTimeout mocks base method. +func (m *MockLDAPClient) SetTimeout(arg0 time.Duration) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetTimeout", arg0) +} + +// SetTimeout indicates an expected call of SetTimeout. +func (mr *MockLDAPClientMockRecorder) SetTimeout(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimeout", reflect.TypeOf((*MockLDAPClient)(nil).SetTimeout), arg0) +} + +// SimpleBind mocks base method. +func (m *MockLDAPClient) SimpleBind(arg0 *ldap.SimpleBindRequest) (*ldap.SimpleBindResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SimpleBind", arg0) + ret0, _ := ret[0].(*ldap.SimpleBindResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SimpleBind indicates an expected call of SimpleBind. +func (mr *MockLDAPClientMockRecorder) SimpleBind(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimpleBind", reflect.TypeOf((*MockLDAPClient)(nil).SimpleBind), arg0) +} + +// Start mocks base method. +func (m *MockLDAPClient) Start() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Start") +} + +// Start indicates an expected call of Start. +func (mr *MockLDAPClientMockRecorder) Start() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockLDAPClient)(nil).Start)) +} + // StartTLS mocks base method. func (m *MockLDAPClient) StartTLS(arg0 *tls.Config) error { m.ctrl.T.Helper() @@ -119,6 +360,21 @@ func (mr *MockLDAPClientMockRecorder) StartTLS(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartTLS", reflect.TypeOf((*MockLDAPClient)(nil).StartTLS), arg0) } +// TLSConnectionState mocks base method. +func (m *MockLDAPClient) TLSConnectionState() (tls.ConnectionState, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TLSConnectionState") + ret0, _ := ret[0].(tls.ConnectionState) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// TLSConnectionState indicates an expected call of TLSConnectionState. +func (mr *MockLDAPClientMockRecorder) TLSConnectionState() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TLSConnectionState", reflect.TypeOf((*MockLDAPClient)(nil).TLSConnectionState)) +} + // UnauthenticatedBind mocks base method. func (m *MockLDAPClient) UnauthenticatedBind(arg0 string) error { m.ctrl.T.Helper() @@ -132,3 +388,32 @@ func (mr *MockLDAPClientMockRecorder) UnauthenticatedBind(arg0 interface{}) *gom mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnauthenticatedBind", reflect.TypeOf((*MockLDAPClient)(nil).UnauthenticatedBind), arg0) } + +// Unbind mocks base method. +func (m *MockLDAPClient) Unbind() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Unbind") + ret0, _ := ret[0].(error) + return ret0 +} + +// Unbind indicates an expected call of Unbind. +func (mr *MockLDAPClientMockRecorder) Unbind() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unbind", reflect.TypeOf((*MockLDAPClient)(nil).Unbind)) +} + +// WhoAmI mocks base method. +func (m *MockLDAPClient) WhoAmI(arg0 []ldap.Control) (*ldap.WhoAmIResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WhoAmI", arg0) + ret0, _ := ret[0].(*ldap.WhoAmIResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WhoAmI indicates an expected call of WhoAmI. +func (mr *MockLDAPClientMockRecorder) WhoAmI(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WhoAmI", reflect.TypeOf((*MockLDAPClient)(nil).WhoAmI), arg0) +} diff --git a/internal/authentication/types.go b/internal/authentication/types.go index 5299185fc..7c2828f8f 100644 --- a/internal/authentication/types.go +++ b/internal/authentication/types.go @@ -3,6 +3,7 @@ package authentication import ( "crypto/tls" "net/mail" + "time" "github.com/go-ldap/ldap/v3" "golang.org/x/text/encoding/unicode" @@ -17,16 +18,39 @@ type LDAPClientFactory interface { // // Methods added to this interface that have a direct correlation with one from ldap.Client should have the same signature. type LDAPClient interface { + Start() Close() + IsClosing() bool + SetTimeout(timeout time.Duration) + + TLSConnectionState() (state tls.ConnectionState, ok bool) StartTLS(config *tls.Config) (err error) + Unbind() (err error) Bind(username, password string) (err error) + SimpleBind(request *ldap.SimpleBindRequest) (result *ldap.SimpleBindResult, err error) + MD5Bind(host string, username string, password string) (err error) + DigestMD5Bind(request *ldap.DigestMD5BindRequest) (result *ldap.DigestMD5BindResult, err error) UnauthenticatedBind(username string) (err error) + ExternalBind() (err error) + NTLMBind(domain string, username string, password string) (err error) + NTLMUnauthenticatedBind(domain string, username string) (err error) + NTLMBindWithHash(domain string, username string, hash string) (err error) + NTLMChallengeBind(request *ldap.NTLMBindRequest) (result *ldap.NTLMBindResult, err error) - Modify(modifyRequest *ldap.ModifyRequest) (err error) - PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) (pwdModifyResult *ldap.PasswordModifyResult, err error) + Modify(request *ldap.ModifyRequest) (err error) + ModifyWithResult(request *ldap.ModifyRequest) (result *ldap.ModifyResult, err error) + ModifyDN(m *ldap.ModifyDNRequest) (err error) + PasswordModify(request *ldap.PasswordModifyRequest) (result *ldap.PasswordModifyResult, err error) - Search(searchRequest *ldap.SearchRequest) (searchResult *ldap.SearchResult, err error) + Add(request *ldap.AddRequest) (err error) + Del(request *ldap.DelRequest) (err error) + + Search(request *ldap.SearchRequest) (result *ldap.SearchResult, err error) + SearchWithPaging(request *ldap.SearchRequest, pagingSize uint32) (result *ldap.SearchResult, err error) + Compare(dn string, attribute string, value string) (same bool, err error) + + WhoAmI(controls []ldap.Control) (result *ldap.WhoAmIResult, err error) } // UserDetails represent the details retrieved for a given user. diff --git a/internal/commands/const.go b/internal/commands/const.go index 2f628fa18..b26c1e94b 100644 --- a/internal/commands/const.go +++ b/internal/commands/const.go @@ -775,7 +775,7 @@ Layouts: ) const ( - fmtLogServerListening = "Server is listening for %s connections on '%s' path '%s'" + fmtLogServerListening = "Listening for %s connections on '%s' path '%s'" ) const (