mirror of
https://github.com/pgsty/minio.git
synced 2026-10-29 12:07:20 +03:00
fix(iam): treat IAM record names too long for the drive as absent
Since RELEASE.2026-09-16T00-00-00Z, LDAP users whose normalized DN is longer than 255 bytes cannot log in. NormDN hex-escapes every non-ASCII byte (go-ldap DN.String()), so one Cyrillic letter takes six characters. IAM looks up records named after the DN: the parent revision check added with cmd/iam-revision.go reads config/iam/users/<DN>/identity.json, and PolicyDBGet reads config/iam/policydb/sts-users/<DN>.json when the mapping is not cached. A drive rejects such an element in one of two ways. checkPathLength refuses more than 255 counted characters, but outside Windows it never counts a backslash, so an escaped DN usually passes it. The filesystem then fails with ENAMETOOLONG once the parent directory exists. toObjectErr reports both as ObjectNameInvalid, and the callers treat only errConfigNotFound as "no record". As a result, AssumeRoleWithLDAPIdentity, access-key creation and STS loading fail. Such a record cannot have been stored. When the object layer's own name validation (checkBucketAndObjectNames) accepts the path, ObjectNameInvalid can only mean a length rejection, so report it as errConfigNotFound. Invalid names and storage errors are returned unchanged, and saving such a record still fails. The etcd store has no such limit and is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: GL <g@lopatin.info>
This commit is contained in:
@@ -134,9 +134,30 @@ func decryptData(data []byte, objPath string) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// iamConfigNameTooLong reports whether the drives rejected objPath for its
|
||||
// length. IAM records are named after external identities: a normalized LDAP
|
||||
// DN hex-escapes every non-ASCII byte, so one Cyrillic letter takes six
|
||||
// characters. Such a record cannot have been stored. checkPathLength does not
|
||||
// count backslashes outside Windows, so an escaped DN can pass it and still
|
||||
// fail on the filesystem with ENAMETOOLONG once its parent directory exists.
|
||||
// toObjectErr reports both as ObjectNameInvalid, as it does for names that the
|
||||
// object layer rejects itself; repeat that validation to tell them apart.
|
||||
func iamConfigNameTooLong(objPath string, err error) bool {
|
||||
if errors.Is(err, errFileNameTooLong) {
|
||||
return true
|
||||
}
|
||||
var invalid ObjectNameInvalid
|
||||
return errors.As(err, &invalid) && checkBucketAndObjectNames(context.Background(), minioMetaBucket, objPath) == nil
|
||||
}
|
||||
|
||||
func (iamOS *IAMObjectStore) loadIAMConfigBytesWithMetadata(ctx context.Context, objPath string) ([]byte, ObjectInfo, error) {
|
||||
data, meta, err := readConfigWithMetadata(ctx, iamOS.objAPI, objPath, ObjectOptions{})
|
||||
if err != nil {
|
||||
if iamConfigNameTooLong(objPath, err) {
|
||||
// A missing record, not a storage failure: lookups of the
|
||||
// identity proceed, while saving its record still fails.
|
||||
err = errConfigNotFound
|
||||
}
|
||||
return nil, meta, err
|
||||
}
|
||||
data, err = decryptData(data, objPath)
|
||||
|
||||
Reference in New Issue
Block a user