feat(authentication): use the passwordmodify exop for pwd resets with ldap (#2124)
Implement the LDAP password modify extended operation for LDAP providers that advertise they support it.pull/2157/head
parent
565515646a
commit
8ee0597486
|
@ -15,6 +15,7 @@ type LDAPConnection interface {
|
|||
|
||||
Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error)
|
||||
Modify(modifyRequest *ldap.ModifyRequest) error
|
||||
PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) error
|
||||
StartTLS(config *tls.Config) error
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,12 @@ func (lc *LDAPConnectionImpl) Modify(modifyRequest *ldap.ModifyRequest) error {
|
|||
return lc.conn.Modify(modifyRequest)
|
||||
}
|
||||
|
||||
// PasswordModify modifies an ldap objects password.
|
||||
func (lc *LDAPConnectionImpl) PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) error {
|
||||
_, err := lc.conn.PasswordModify(pwdModifyRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
// StartTLS requests the LDAP server upgrades to TLS encryption.
|
||||
func (lc *LDAPConnectionImpl) StartTLS(config *tls.Config) error {
|
||||
return lc.conn.StartTLS(config)
|
||||
|
|
|
@ -88,6 +88,20 @@ func (mr *MockLDAPConnectionMockRecorder) Modify(modifyRequest interface{}) *gom
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockLDAPConnection)(nil).Modify), modifyRequest)
|
||||
}
|
||||
|
||||
// PasswordModify mocks base method
|
||||
func (m *MockLDAPConnection) PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordModify", pwdModifyRequest)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PasswordModify indicates an expected call of PasswordModify
|
||||
func (mr *MockLDAPConnectionMockRecorder) PasswordModify(pwdModifyRequest interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordModify", reflect.TypeOf((*MockLDAPConnection)(nil).Modify), pwdModifyRequest)
|
||||
}
|
||||
|
||||
// StartTLS mocks base method
|
||||
func (m *MockLDAPConnection) StartTLS(config *tls.Config) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -342,20 +342,30 @@ func (p *LDAPUserProvider) UpdatePassword(inputUsername string, newPassword stri
|
|||
return fmt.Errorf("Unable to update password. Cause: %s", err)
|
||||
}
|
||||
|
||||
modifyRequest := ldap.NewModifyRequest(profile.DN, nil)
|
||||
switch {
|
||||
case p.supportExtensionPasswdModify:
|
||||
modifyRequest := ldap.NewPasswordModifyRequest(
|
||||
profile.DN,
|
||||
"",
|
||||
newPassword,
|
||||
)
|
||||
|
||||
switch p.configuration.Implementation {
|
||||
case schema.LDAPImplementationActiveDirectory:
|
||||
err = conn.PasswordModify(modifyRequest)
|
||||
case p.configuration.Implementation == schema.LDAPImplementationActiveDirectory:
|
||||
modifyRequest := ldap.NewModifyRequest(profile.DN, nil)
|
||||
utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
|
||||
// The password needs to be enclosed in quotes
|
||||
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2
|
||||
pwdEncoded, _ := utf16.NewEncoder().String(fmt.Sprintf("\"%s\"", newPassword))
|
||||
modifyRequest.Replace("unicodePwd", []string{pwdEncoded})
|
||||
default:
|
||||
modifyRequest.Replace("userPassword", []string{newPassword})
|
||||
}
|
||||
|
||||
err = conn.Modify(modifyRequest)
|
||||
err = conn.Modify(modifyRequest)
|
||||
default:
|
||||
modifyRequest := ldap.NewModifyRequest(profile.DN, nil)
|
||||
modifyRequest.Replace("userPassword", []string{newPassword})
|
||||
|
||||
err = conn.Modify(modifyRequest)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to update password. Cause: %s", err)
|
||||
|
|
|
@ -649,10 +649,36 @@ func TestShouldUpdateUserPassword(t *testing.T) {
|
|||
nil,
|
||||
mockFactory)
|
||||
|
||||
modifyRequest := ldap.NewModifyRequest("uid=test,dc=example,dc=com", nil)
|
||||
modifyRequest.Replace("userPassword", []string{"password"})
|
||||
pwdModifyRequest := ldap.NewPasswordModifyRequest(
|
||||
"uid=test,dc=example,dc=com",
|
||||
"",
|
||||
"password",
|
||||
)
|
||||
|
||||
gomock.InOrder(
|
||||
mockFactory.EXPECT().
|
||||
DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()).
|
||||
Return(mockConn, nil),
|
||||
mockConn.EXPECT().
|
||||
Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
|
||||
Return(nil),
|
||||
|
||||
mockConn.EXPECT().
|
||||
Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute})).
|
||||
Return(&ldap.SearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: ldapSupportedExtensionAttribute,
|
||||
Values: []string{ldapOIDPasswdModifyExtension},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil),
|
||||
|
||||
mockFactory.EXPECT().
|
||||
DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()).
|
||||
Return(mockConn, nil),
|
||||
|
@ -683,14 +709,16 @@ func TestShouldUpdateUserPassword(t *testing.T) {
|
|||
},
|
||||
}, nil),
|
||||
mockConn.EXPECT().
|
||||
Modify(modifyRequest).
|
||||
PasswordModify(pwdModifyRequest).
|
||||
Return(nil),
|
||||
mockConn.EXPECT().
|
||||
Close(),
|
||||
)
|
||||
|
||||
err := ldapClient.UpdatePassword("john", "password")
|
||||
err := ldapClient.checkServer()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ldapClient.UpdatePassword("john", "password")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue