mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-19 22:44:18 +00:00
Check for locked users on ad upstream refresh
Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
+1
-1
@@ -317,7 +317,7 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context,
|
||||
},
|
||||
Dialer: c.ldapDialer,
|
||||
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 == "" {
|
||||
|
||||
+70
-15
@@ -221,7 +221,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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.
|
||||
@@ -538,7 +542,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -595,7 +603,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: "sAMAccountName",
|
||||
},
|
||||
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{{
|
||||
@@ -655,7 +667,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -715,7 +731,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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(),
|
||||
@@ -774,7 +794,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -904,7 +928,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -1029,8 +1057,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||
@@ -1081,7 +1112,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -1282,7 +1317,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
},
|
||||
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": upstreamldap.MicrosoftUUIDFromBinary("objectGUID")},
|
||||
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{{
|
||||
@@ -1335,7 +1374,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -1392,7 +1435,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -1443,7 +1490,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
@@ -1640,7 +1691,11 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
||||
GroupNameAttribute: testGroupNameAttrName,
|
||||
},
|
||||
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{{
|
||||
|
||||
@@ -41,8 +41,11 @@ const (
|
||||
defaultLDAPPort = uint16(389)
|
||||
defaultLDAPSPort = uint16(636)
|
||||
sAMAccountNameAttribute = "sAMAccountName"
|
||||
pwdLastSetAttribute = "pwdLastSet"
|
||||
userAccountControlAttribute = "userAccountControl"
|
||||
PwdLastSetAttribute = "pwdLastSet"
|
||||
UserAccountControlAttribute = "userAccountControl"
|
||||
UserAccountControlComputedAttribute = "msDS-User-Account-Control-Computed"
|
||||
accountDisabledBitmapValue = 2
|
||||
accountLockedBitmapValue = 16
|
||||
)
|
||||
|
||||
// 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 {
|
||||
authTime := attributes.AuthTime
|
||||
pwdLastSetWin32Format := entry.GetAttributeValues(pwdLastSetAttribute)
|
||||
pwdLastSetWin32Format := entry.GetAttributeValues(PwdLastSetAttribute)
|
||||
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
|
||||
pwdLastSetParsed, err := win32timestampToTime(pwdLastSetWin32Format[0])
|
||||
@@ -898,14 +901,27 @@ func win32timestampToTime(win32timestamp string) (*time.Time, 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
deactivated := userAccountControl & 2 // bitwise and.
|
||||
deactivated := userAccountControl & accountDisabledBitmapValue // bitwise and.
|
||||
if deactivated != 0 {
|
||||
return fmt.Errorf("user has been deactivated")
|
||||
}
|
||||
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"
|
||||
"time"
|
||||
|
||||
provider2 "go.pinniped.dev/internal/oidc/provider"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -28,6 +26,7 @@ import (
|
||||
"go.pinniped.dev/internal/crypto/ptls"
|
||||
"go.pinniped.dev/internal/endpointaddr"
|
||||
"go.pinniped.dev/internal/mocks/mockldapconn"
|
||||
provider2 "go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user