Check for locked users on ad upstream refresh
Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
parent
f62e9a2d33
commit
ef5a04c7ce
@ -317,7 +317,7 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context,
|
|||||||
},
|
},
|
||||||
Dialer: c.ldapDialer,
|
Dialer: c.ldapDialer,
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{upstreamldap.PwdLastSetAttribute: upstreamldap.PwdUnchangedSinceLogin, upstreamldap.UserAccountControlAttribute: upstreamldap.ValidUserAccountControl, upstreamldap.UserAccountControlComputedAttribute: upstreamldap.ValidComputedUserAccountControl},
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.GroupSearch.Attributes.GroupName == "" {
|
if spec.GroupSearch.Attributes.GroupName == "" {
|
||||||
|
@ -221,7 +221,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a copy with targeted changes.
|
// Make a copy with targeted changes.
|
||||||
@ -538,7 +542,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -595,7 +603,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: "sAMAccountName",
|
GroupNameAttribute: "sAMAccountName",
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -655,7 +667,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -715,7 +731,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
@ -774,7 +794,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -904,7 +928,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1029,8 +1057,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
},
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
@ -1081,7 +1112,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1282,7 +1317,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
GroupAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"sAMAccountName": upstreamldap.GroupSAMAccountNameWithDomainSuffix},
|
GroupAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"sAMAccountName": upstreamldap.GroupSAMAccountNameWithDomainSuffix},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1335,7 +1374,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1392,7 +1435,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1443,7 +1490,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
@ -1640,7 +1691,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
GroupNameAttribute: testGroupNameAttrName,
|
GroupNameAttribute: testGroupNameAttrName,
|
||||||
},
|
},
|
||||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||||
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin, "userAccountControl": upstreamldap.ValidUserAccountControl},
|
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{
|
||||||
|
"pwdLastSet": upstreamldap.PwdUnchangedSinceLogin,
|
||||||
|
"userAccountControl": upstreamldap.ValidUserAccountControl,
|
||||||
|
"msDS-User-Account-Control-Computed": upstreamldap.ValidComputedUserAccountControl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
|
@ -41,8 +41,11 @@ const (
|
|||||||
defaultLDAPPort = uint16(389)
|
defaultLDAPPort = uint16(389)
|
||||||
defaultLDAPSPort = uint16(636)
|
defaultLDAPSPort = uint16(636)
|
||||||
sAMAccountNameAttribute = "sAMAccountName"
|
sAMAccountNameAttribute = "sAMAccountName"
|
||||||
pwdLastSetAttribute = "pwdLastSet"
|
PwdLastSetAttribute = "pwdLastSet"
|
||||||
userAccountControlAttribute = "userAccountControl"
|
UserAccountControlAttribute = "userAccountControl"
|
||||||
|
UserAccountControlComputedAttribute = "msDS-User-Account-Control-Computed"
|
||||||
|
accountDisabledBitmapValue = 2
|
||||||
|
accountLockedBitmapValue = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn abstracts the upstream LDAP communication protocol (mostly for testing).
|
// Conn abstracts the upstream LDAP communication protocol (mostly for testing).
|
||||||
@ -860,9 +863,9 @@ func getDomainFromDistinguishedName(distinguishedName string) (string, error) {
|
|||||||
|
|
||||||
func PwdUnchangedSinceLogin(entry *ldap.Entry, attributes provider.StoredRefreshAttributes) error {
|
func PwdUnchangedSinceLogin(entry *ldap.Entry, attributes provider.StoredRefreshAttributes) error {
|
||||||
authTime := attributes.AuthTime
|
authTime := attributes.AuthTime
|
||||||
pwdLastSetWin32Format := entry.GetAttributeValues(pwdLastSetAttribute)
|
pwdLastSetWin32Format := entry.GetAttributeValues(PwdLastSetAttribute)
|
||||||
if len(pwdLastSetWin32Format) != 1 {
|
if len(pwdLastSetWin32Format) != 1 {
|
||||||
return fmt.Errorf("expected to find 1 value for %s attribute, but found %d", pwdLastSetAttribute, len(pwdLastSetWin32Format))
|
return fmt.Errorf("expected to find 1 value for %s attribute, but found %d", PwdLastSetAttribute, len(pwdLastSetWin32Format))
|
||||||
}
|
}
|
||||||
// convert to a time.Time
|
// convert to a time.Time
|
||||||
pwdLastSetParsed, err := win32timestampToTime(pwdLastSetWin32Format[0])
|
pwdLastSetParsed, err := win32timestampToTime(pwdLastSetWin32Format[0])
|
||||||
@ -898,14 +901,27 @@ func win32timestampToTime(win32timestamp string) (*time.Time, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ValidUserAccountControl(entry *ldap.Entry, _ provider.StoredRefreshAttributes) error {
|
func ValidUserAccountControl(entry *ldap.Entry, _ provider.StoredRefreshAttributes) error {
|
||||||
userAccountControl, err := strconv.Atoi(entry.GetAttributeValue(userAccountControlAttribute))
|
userAccountControl, err := strconv.Atoi(entry.GetAttributeValue(UserAccountControlAttribute))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivated := userAccountControl & 2 // bitwise and.
|
deactivated := userAccountControl & accountDisabledBitmapValue // bitwise and.
|
||||||
if deactivated != 0 {
|
if deactivated != 0 {
|
||||||
return fmt.Errorf("user has been deactivated")
|
return fmt.Errorf("user has been deactivated")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValidComputedUserAccountControl(entry *ldap.Entry, _ provider.StoredRefreshAttributes) error {
|
||||||
|
userAccountControl, err := strconv.Atoi(entry.GetAttributeValue(UserAccountControlComputedAttribute))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
locked := userAccountControl & accountLockedBitmapValue // bitwise and
|
||||||
|
if locked != 0 {
|
||||||
|
return fmt.Errorf("user has been locked")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -16,8 +16,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
provider2 "go.pinniped.dev/internal/oidc/provider"
|
|
||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -28,6 +26,7 @@ import (
|
|||||||
"go.pinniped.dev/internal/crypto/ptls"
|
"go.pinniped.dev/internal/crypto/ptls"
|
||||||
"go.pinniped.dev/internal/endpointaddr"
|
"go.pinniped.dev/internal/endpointaddr"
|
||||||
"go.pinniped.dev/internal/mocks/mockldapconn"
|
"go.pinniped.dev/internal/mocks/mockldapconn"
|
||||||
|
provider2 "go.pinniped.dev/internal/oidc/provider"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
"go.pinniped.dev/internal/testutil/tlsserver"
|
"go.pinniped.dev/internal/testutil/tlsserver"
|
||||||
)
|
)
|
||||||
@ -2152,3 +2151,51 @@ func TestValidUserAccountControl(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidComputedUserAccountControl(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
entry *ldap.Entry
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy normal user",
|
||||||
|
entry: &ldap.Entry{
|
||||||
|
DN: "some-dn",
|
||||||
|
Attributes: []*ldap.EntryAttribute{
|
||||||
|
{
|
||||||
|
Name: "msDS-User-Account-Control-Computed",
|
||||||
|
Values: []string{"0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "locked user",
|
||||||
|
entry: &ldap.Entry{
|
||||||
|
DN: "some-dn",
|
||||||
|
Attributes: []*ldap.EntryAttribute{
|
||||||
|
{
|
||||||
|
Name: "msDS-User-Account-Control-Computed",
|
||||||
|
Values: []string{"16"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: "user has been locked",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
tt := test
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := ValidComputedUserAccountControl(tt.entry, provider2.StoredRefreshAttributes{})
|
||||||
|
|
||||||
|
if tt.wantErr != "" {
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, tt.wantErr, err.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -45,6 +45,7 @@ import (
|
|||||||
"go.pinniped.dev/test/testlib/browsertest"
|
"go.pinniped.dev/test/testlib/browsertest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint:gocyclo
|
||||||
func TestSupervisorLogin(t *testing.T) {
|
func TestSupervisorLogin(t *testing.T) {
|
||||||
env := testlib.IntegrationEnv(t)
|
env := testlib.IntegrationEnv(t)
|
||||||
|
|
||||||
@ -1024,6 +1025,68 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantDownstreamIDTokenGroups: []string{}, // none for now.
|
wantDownstreamIDTokenGroups: []string{}, // none for now.
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "active directory login fails after the user is locked",
|
||||||
|
maybeSkip: func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
if len(env.ToolsNamespace) == 0 && !env.HasCapability(testlib.CanReachInternetLDAPPorts) {
|
||||||
|
t.Skip("LDAP integration test requires connectivity to an LDAP server")
|
||||||
|
}
|
||||||
|
if env.SupervisorUpstreamActiveDirectory.Host == "" {
|
||||||
|
t.Skip("Active Directory hostname not specified")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createIDP: func(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
secret := testlib.CreateTestSecret(t, env.SupervisorNamespace, "ad-service-account", v1.SecretTypeBasicAuth,
|
||||||
|
map[string]string{
|
||||||
|
v1.BasicAuthUsernameKey: env.SupervisorUpstreamActiveDirectory.BindUsername,
|
||||||
|
v1.BasicAuthPasswordKey: env.SupervisorUpstreamActiveDirectory.BindPassword,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
adIDP := testlib.CreateTestActiveDirectoryIdentityProvider(t, idpv1alpha1.ActiveDirectoryIdentityProviderSpec{
|
||||||
|
Host: env.SupervisorUpstreamActiveDirectory.Host,
|
||||||
|
TLS: &idpv1alpha1.TLSSpec{
|
||||||
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamActiveDirectory.CABundle)),
|
||||||
|
},
|
||||||
|
Bind: idpv1alpha1.ActiveDirectoryIdentityProviderBind{
|
||||||
|
SecretName: secret.Name,
|
||||||
|
},
|
||||||
|
}, idpv1alpha1.ActiveDirectoryPhaseReady)
|
||||||
|
expectedMsg := fmt.Sprintf(
|
||||||
|
`successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`,
|
||||||
|
env.SupervisorUpstreamActiveDirectory.Host, env.SupervisorUpstreamActiveDirectory.BindUsername,
|
||||||
|
secret.Name, secret.ResourceVersion,
|
||||||
|
)
|
||||||
|
requireSuccessfulActiveDirectoryIdentityProviderConditions(t, adIDP, expectedMsg)
|
||||||
|
return adIDP.Name
|
||||||
|
},
|
||||||
|
createTestUser: func(t *testing.T) (string, string) {
|
||||||
|
return createFreshADTestUser(t, env)
|
||||||
|
},
|
||||||
|
deleteTestUser: func(t *testing.T, username string) {
|
||||||
|
deleteTestADUser(t, env, username)
|
||||||
|
},
|
||||||
|
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _, testUserName, testUserPassword string, httpClient *http.Client) {
|
||||||
|
requestAuthorizationUsingCLIPasswordFlow(t,
|
||||||
|
downstreamAuthorizeURL,
|
||||||
|
testUserName, // username to present to server during login
|
||||||
|
testUserPassword, // password to present to server during login
|
||||||
|
httpClient,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
breakRefreshSessionData: func(t *testing.T, sessionData *psession.PinnipedSession, _, username string) {
|
||||||
|
lockADTestUser(t, env, username)
|
||||||
|
},
|
||||||
|
// we can't know the subject ahead of time because we created a new user and don't know their uid,
|
||||||
|
// so skip wantDownstreamIDTokenSubjectToMatch
|
||||||
|
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
||||||
|
wantDownstreamIDTokenUsernameToMatch: func(username string) string {
|
||||||
|
return "^" + regexp.QuoteMeta(username+"@"+env.SupervisorUpstreamActiveDirectory.Domain) + "$"
|
||||||
|
},
|
||||||
|
wantDownstreamIDTokenGroups: []string{},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "logging in to activedirectory with a deactivated user fails",
|
name: "logging in to activedirectory with a deactivated user fails",
|
||||||
maybeSkip: func(t *testing.T) {
|
maybeSkip: func(t *testing.T) {
|
||||||
@ -1153,7 +1216,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
"&sub="+base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeValue)),
|
"&sub="+base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeValue)),
|
||||||
) + "$",
|
) + "$",
|
||||||
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
||||||
wantDownstreamIDTokenUsernameToMatch: func(username string) string {
|
wantDownstreamIDTokenUsernameToMatch: func(_ string) string {
|
||||||
return "^" + regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserMailAttributeValue) + "$"
|
return "^" + regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserMailAttributeValue) + "$"
|
||||||
},
|
},
|
||||||
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs,
|
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs,
|
||||||
@ -1788,10 +1851,12 @@ func createFreshADTestUser(t *testing.T, env *testlib.TestEnv) (string, string)
|
|||||||
m.Replace("userAccountControl", []string{"512"})
|
m.Replace("userAccountControl", []string{"512"})
|
||||||
err = conn.Modify(m)
|
err = conn.Modify(m)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(20 * time.Second) // intrasite domain controller replication can take up to 15 seconds, so wait to ensure the change has propogated.
|
||||||
return testUserName, testUserPassword
|
return testUserName, testUserPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
// deactivate the test user's password
|
// deactivate the test user.
|
||||||
func deactivateADTestUser(t *testing.T, env *testlib.TestEnv, testUserName string) {
|
func deactivateADTestUser(t *testing.T, env *testlib.TestEnv, testUserName string) {
|
||||||
conn := dialTLS(t, env)
|
conn := dialTLS(t, env)
|
||||||
// bind
|
// bind
|
||||||
@ -1803,6 +1868,24 @@ func deactivateADTestUser(t *testing.T, env *testlib.TestEnv, testUserName strin
|
|||||||
m.Replace("userAccountControl", []string{"514"}) // normal user, account disabled
|
m.Replace("userAccountControl", []string{"514"}) // normal user, account disabled
|
||||||
err = conn.Modify(m)
|
err = conn.Modify(m)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(20 * time.Second) // intrasite domain controller replication can take up to 15 seconds, so wait to ensure the change has propogated.
|
||||||
|
}
|
||||||
|
|
||||||
|
// lock the test user's account by entering the wrong password a bunch of times.
|
||||||
|
func lockADTestUser(t *testing.T, env *testlib.TestEnv, testUserName string) {
|
||||||
|
userDN := fmt.Sprintf("CN=%s,OU=test-users,%s", testUserName, env.SupervisorUpstreamActiveDirectory.UserSearchBase)
|
||||||
|
conn := dialTLS(t, env)
|
||||||
|
|
||||||
|
for i := 0; i <= 21; i++ { // our password policy allows 20 wrong attempts before locking the account, so do 21.
|
||||||
|
err := conn.Bind(userDN, "not-the-right-password-"+fmt.Sprint(i))
|
||||||
|
require.Error(t, err) // this should be an error
|
||||||
|
}
|
||||||
|
|
||||||
|
err := conn.Bind(env.SupervisorUpstreamActiveDirectory.BindUsername, env.SupervisorUpstreamActiveDirectory.BindPassword)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(20 * time.Second) // intrasite domain controller replication can take up to 15 seconds, so wait to ensure the change has propogated.
|
||||||
}
|
}
|
||||||
|
|
||||||
// change the user's password to a new one.
|
// change the user's password to a new one.
|
||||||
@ -1822,13 +1905,14 @@ func changeADTestUserPassword(t *testing.T, env *testlib.TestEnv, testUserName s
|
|||||||
m.Replace("unicodePwd", []string{encodedTestUserPassword})
|
m.Replace("unicodePwd", []string{encodedTestUserPassword})
|
||||||
err = conn.Modify(m)
|
err = conn.Modify(m)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(20 * time.Second) // intrasite domain controller replication can take up to 15 seconds, so wait to ensure the change has propogated.
|
||||||
// don't bother to return the new password... we won't be using it, just checking that it's changed.
|
// don't bother to return the new password... we won't be using it, just checking that it's changed.
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the test user created for this test.
|
// delete the test user created for this test.
|
||||||
func deleteTestADUser(t *testing.T, env *testlib.TestEnv, testUserName string) {
|
func deleteTestADUser(t *testing.T, env *testlib.TestEnv, testUserName string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
conn := dialTLS(t, env)
|
conn := dialTLS(t, env)
|
||||||
// bind
|
// bind
|
||||||
err := conn.Bind(env.SupervisorUpstreamActiveDirectory.BindUsername, env.SupervisorUpstreamActiveDirectory.BindPassword)
|
err := conn.Bind(env.SupervisorUpstreamActiveDirectory.BindUsername, env.SupervisorUpstreamActiveDirectory.BindPassword)
|
||||||
|
Loading…
Reference in New Issue
Block a user