storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/sts-handlers.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018-2020 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/base64"
    23  	"fmt"
    24  	"net/http"
    25  	"strings"
    26  
    27  	"github.com/gorilla/mux"
    28  
    29  	"storj.io/minio/cmd/config/identity/openid"
    30  	xhttp "storj.io/minio/cmd/http"
    31  	"storj.io/minio/cmd/logger"
    32  	"storj.io/minio/pkg/auth"
    33  	iampolicy "storj.io/minio/pkg/iam/policy"
    34  	"storj.io/minio/pkg/wildcard"
    35  )
    36  
    37  const (
    38  	// STS API version.
    39  	stsAPIVersion       = "2011-06-15"
    40  	stsVersion          = "Version"
    41  	stsAction           = "Action"
    42  	stsPolicy           = "Policy"
    43  	stsToken            = "Token"
    44  	stsWebIdentityToken = "WebIdentityToken"
    45  	stsDurationSeconds  = "DurationSeconds"
    46  	stsLDAPUsername     = "LDAPUsername"
    47  	stsLDAPPassword     = "LDAPPassword"
    48  
    49  	// STS API action constants
    50  	clientGrants = "AssumeRoleWithClientGrants"
    51  	webIdentity  = "AssumeRoleWithWebIdentity"
    52  	ldapIdentity = "AssumeRoleWithLDAPIdentity"
    53  	assumeRole   = "AssumeRole"
    54  
    55  	stsRequestBodyLimit = 10 * (1 << 20) // 10 MiB
    56  
    57  	// JWT claim keys
    58  	expClaim = "exp"
    59  	subClaim = "sub"
    60  
    61  	// JWT claim to check the parent user
    62  	parentClaim = "parent"
    63  
    64  	// LDAP claim keys
    65  	ldapUser = "ldapUser"
    66  )
    67  
    68  // stsAPIHandlers implements and provides http handlers for AWS STS API.
    69  type stsAPIHandlers struct{}
    70  
    71  // registerSTSRouter - registers AWS STS compatible APIs.
    72  func registerSTSRouter(router *mux.Router) {
    73  	// Initialize STS.
    74  	sts := &stsAPIHandlers{}
    75  
    76  	// STS Router
    77  	stsRouter := router.NewRoute().PathPrefix(SlashSeparator).Subrouter()
    78  
    79  	// Assume roles with no JWT, handles AssumeRole.
    80  	stsRouter.Methods(http.MethodPost).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
    81  		ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType))
    82  		authOk := wildcard.MatchSimple(signV4Algorithm+"*", r.Header.Get(xhttp.Authorization))
    83  		noQueries := len(r.URL.Query()) == 0
    84  		return ctypeOk && authOk && noQueries
    85  	}).HandlerFunc(HTTPTraceAll(sts.AssumeRole))
    86  
    87  	// Assume roles with JWT handler, handles both ClientGrants and WebIdentity.
    88  	stsRouter.Methods(http.MethodPost).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
    89  		ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType))
    90  		noQueries := len(r.URL.Query()) == 0
    91  		return ctypeOk && noQueries
    92  	}).HandlerFunc(HTTPTraceAll(sts.AssumeRoleWithSSO))
    93  
    94  	// AssumeRoleWithClientGrants
    95  	stsRouter.Methods(http.MethodPost).HandlerFunc(HTTPTraceAll(sts.AssumeRoleWithClientGrants)).
    96  		Queries(stsAction, clientGrants).
    97  		Queries(stsVersion, stsAPIVersion).
    98  		Queries(stsToken, "{Token:.*}")
    99  
   100  	// AssumeRoleWithWebIdentity
   101  	stsRouter.Methods(http.MethodPost).HandlerFunc(HTTPTraceAll(sts.AssumeRoleWithWebIdentity)).
   102  		Queries(stsAction, webIdentity).
   103  		Queries(stsVersion, stsAPIVersion).
   104  		Queries(stsWebIdentityToken, "{Token:.*}")
   105  
   106  	// AssumeRoleWithLDAPIdentity
   107  	stsRouter.Methods(http.MethodPost).HandlerFunc(HTTPTraceAll(sts.AssumeRoleWithLDAPIdentity)).
   108  		Queries(stsAction, ldapIdentity).
   109  		Queries(stsVersion, stsAPIVersion).
   110  		Queries(stsLDAPUsername, "{LDAPUsername:.*}").
   111  		Queries(stsLDAPPassword, "{LDAPPassword:.*}")
   112  }
   113  
   114  func checkAssumeRoleAuth(ctx context.Context, r *http.Request) (user auth.Credentials, isErrCodeSTS bool, stsErr STSErrorCode) {
   115  	switch getRequestAuthType(r) {
   116  	default:
   117  		return user, true, ErrSTSAccessDenied
   118  	case authTypeSigned:
   119  		s3Err := isReqAuthenticated(ctx, r, globalServerRegion, serviceSTS)
   120  		if APIErrorCode(s3Err) != ErrNone {
   121  			return user, false, STSErrorCode(s3Err)
   122  		}
   123  		var owner bool
   124  		user, owner, s3Err = getReqAccessKeyV4(r, globalServerRegion, serviceSTS)
   125  		if APIErrorCode(s3Err) != ErrNone {
   126  			return user, false, STSErrorCode(s3Err)
   127  		}
   128  		// Root credentials are not allowed to use STS API
   129  		if owner {
   130  			return user, true, ErrSTSAccessDenied
   131  		}
   132  	}
   133  
   134  	// Session tokens are not allowed in STS AssumeRole requests.
   135  	if getSessionToken(r) != "" {
   136  		return user, true, ErrSTSAccessDenied
   137  	}
   138  
   139  	// Temporary credentials or Service accounts cannot generate further temporary credentials.
   140  	if user.IsTemp() || user.IsServiceAccount() {
   141  		return user, true, ErrSTSAccessDenied
   142  	}
   143  
   144  	return user, true, ErrSTSNone
   145  }
   146  
   147  // AssumeRole - implementation of AWS STS API AssumeRole to get temporary
   148  // credentials for regular users on Minio.
   149  // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
   150  func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
   151  	ctx := NewContext(r, w, "AssumeRole")
   152  
   153  	user, isErrCodeSTS, stsErr := checkAssumeRoleAuth(ctx, r)
   154  	if stsErr != ErrSTSNone {
   155  		writeSTSErrorResponse(ctx, w, isErrCodeSTS, stsErr, nil)
   156  		return
   157  	}
   158  	if err := r.ParseForm(); err != nil {
   159  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   160  		return
   161  	}
   162  
   163  	if r.Form.Get(stsVersion) != stsAPIVersion {
   164  		writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get(stsVersion), stsAPIVersion))
   165  		return
   166  	}
   167  
   168  	action := r.Form.Get(stsAction)
   169  	switch action {
   170  	case assumeRole:
   171  	default:
   172  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
   173  		return
   174  	}
   175  
   176  	ctx = NewContext(r, w, action)
   177  	defer logger.AuditLog(ctx, w, r, nil)
   178  
   179  	sessionPolicyStr := r.Form.Get(stsPolicy)
   180  	// https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
   181  	// The plain text that you use for both inline and managed session
   182  	// policies shouldn't exceed 2048 characters.
   183  	if len(sessionPolicyStr) > 2048 {
   184  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy shouldn't exceed 2048 characters"))
   185  		return
   186  	}
   187  
   188  	if len(sessionPolicyStr) > 0 {
   189  		sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
   190  		if err != nil {
   191  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   192  			return
   193  		}
   194  
   195  		// Version in policy must not be empty
   196  		if sessionPolicy.Version == "" {
   197  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Version cannot be empty expecting '2012-10-17'"))
   198  			return
   199  		}
   200  	}
   201  
   202  	var err error
   203  	m := make(map[string]interface{})
   204  	m[expClaim], err = openid.GetDefaultExpiration(r.Form.Get(stsDurationSeconds))
   205  	if err != nil {
   206  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   207  		return
   208  	}
   209  
   210  	policies, err := GlobalIAMSys.PolicyDBGet(user.AccessKey, false)
   211  	if err != nil {
   212  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   213  		return
   214  	}
   215  
   216  	policyName := strings.Join(policies, ",")
   217  
   218  	// This policy is the policy associated with the user
   219  	// requesting for temporary credentials. The temporary
   220  	// credentials will inherit the same policy requirements.
   221  	m[iamPolicyClaimNameOpenID()] = policyName
   222  
   223  	if len(sessionPolicyStr) > 0 {
   224  		m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString([]byte(sessionPolicyStr))
   225  	}
   226  
   227  	secret := globalActiveCred.SecretKey
   228  	cred, err := auth.GetNewCredentialsWithMetadata(m, secret)
   229  	if err != nil {
   230  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   231  		return
   232  	}
   233  
   234  	// Set the parent of the temporary access key, this is useful
   235  	// in obtaining service accounts by this cred.
   236  	cred.ParentUser = user.AccessKey
   237  
   238  	// Set the newly generated credentials.
   239  	if err = GlobalIAMSys.SetTempUser(cred.AccessKey, cred, policyName); err != nil {
   240  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   241  		return
   242  	}
   243  
   244  	// Notify all other MinIO peers to reload temp users
   245  	for _, nerr := range GlobalNotificationSys.LoadUser(cred.AccessKey, true) {
   246  		if nerr.Err != nil {
   247  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   248  			logger.LogIf(ctx, nerr.Err)
   249  		}
   250  	}
   251  
   252  	assumeRoleResponse := &AssumeRoleResponse{
   253  		Result: AssumeRoleResult{
   254  			Credentials: cred,
   255  		},
   256  	}
   257  
   258  	assumeRoleResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
   259  	WriteSuccessResponseXML(w, EncodeResponse(assumeRoleResponse))
   260  }
   261  
   262  func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Request) {
   263  	ctx := NewContext(r, w, "AssumeRoleSSOCommon")
   264  
   265  	// Parse the incoming form data.
   266  	if err := r.ParseForm(); err != nil {
   267  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   268  		return
   269  	}
   270  
   271  	if r.Form.Get(stsVersion) != stsAPIVersion {
   272  		writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion))
   273  		return
   274  	}
   275  
   276  	action := r.Form.Get(stsAction)
   277  	switch action {
   278  	case ldapIdentity:
   279  		sts.AssumeRoleWithLDAPIdentity(w, r)
   280  		return
   281  	case clientGrants, webIdentity:
   282  	default:
   283  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
   284  		return
   285  	}
   286  
   287  	ctx = NewContext(r, w, action)
   288  	defer logger.AuditLog(ctx, w, r, nil)
   289  
   290  	if globalOpenIDValidators == nil {
   291  		writeSTSErrorResponse(ctx, w, true, ErrSTSNotInitialized, errServerNotInitialized)
   292  		return
   293  	}
   294  
   295  	v, err := globalOpenIDValidators.Get("jwt")
   296  	if err != nil {
   297  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   298  		return
   299  	}
   300  
   301  	token := r.Form.Get(stsToken)
   302  	if token == "" {
   303  		token = r.Form.Get(stsWebIdentityToken)
   304  	}
   305  
   306  	m, err := v.Validate(token, r.Form.Get(stsDurationSeconds))
   307  	if err != nil {
   308  		switch err {
   309  		case openid.ErrTokenExpired:
   310  			switch action {
   311  			case clientGrants:
   312  				writeSTSErrorResponse(ctx, w, true, ErrSTSClientGrantsExpiredToken, err)
   313  			case webIdentity:
   314  				writeSTSErrorResponse(ctx, w, true, ErrSTSWebIdentityExpiredToken, err)
   315  			}
   316  			return
   317  		case auth.ErrInvalidDuration:
   318  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   319  			return
   320  		}
   321  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   322  		return
   323  	}
   324  
   325  	// JWT has requested a custom claim with policy value set.
   326  	// This is a MinIO STS API specific value, this value should
   327  	// be set and configured on your identity provider as part of
   328  	// JWT custom claims.
   329  	var policyName string
   330  	policySet, ok := iampolicy.GetPoliciesFromClaims(m, iamPolicyClaimNameOpenID())
   331  	if ok {
   332  		policyName = GlobalIAMSys.CurrentPolicies(strings.Join(policySet.ToSlice(), ","))
   333  	}
   334  
   335  	if policyName == "" && GlobalPolicyOPA == nil {
   336  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
   337  			fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID()))
   338  		return
   339  	}
   340  	m[iamPolicyClaimNameOpenID()] = policyName
   341  
   342  	sessionPolicyStr := r.Form.Get(stsPolicy)
   343  	// https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html
   344  	// The plain text that you use for both inline and managed session
   345  	// policies shouldn't exceed 2048 characters.
   346  	if len(sessionPolicyStr) > 2048 {
   347  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters"))
   348  		return
   349  	}
   350  
   351  	if len(sessionPolicyStr) > 0 {
   352  		sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
   353  		if err != nil {
   354  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   355  			return
   356  		}
   357  
   358  		// Version in policy must not be empty
   359  		if sessionPolicy.Version == "" {
   360  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Invalid session policy version"))
   361  			return
   362  		}
   363  
   364  		m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString([]byte(sessionPolicyStr))
   365  	}
   366  
   367  	secret := globalActiveCred.SecretKey
   368  	cred, err := auth.GetNewCredentialsWithMetadata(m, secret)
   369  	if err != nil {
   370  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   371  		return
   372  	}
   373  
   374  	var subFromToken string
   375  	if v, ok := m[subClaim]; ok {
   376  		subFromToken, _ = v.(string)
   377  	}
   378  
   379  	// Set the newly generated credentials.
   380  	if err = GlobalIAMSys.SetTempUser(cred.AccessKey, cred, policyName); err != nil {
   381  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   382  		return
   383  	}
   384  
   385  	// Notify all other MinIO peers to reload temp users
   386  	for _, nerr := range GlobalNotificationSys.LoadUser(cred.AccessKey, true) {
   387  		if nerr.Err != nil {
   388  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   389  			logger.LogIf(ctx, nerr.Err)
   390  		}
   391  	}
   392  
   393  	var encodedSuccessResponse []byte
   394  	switch action {
   395  	case clientGrants:
   396  		clientGrantsResponse := &AssumeRoleWithClientGrantsResponse{
   397  			Result: ClientGrantsResult{
   398  				Credentials:      cred,
   399  				SubjectFromToken: subFromToken,
   400  			},
   401  		}
   402  		clientGrantsResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
   403  		encodedSuccessResponse = EncodeResponse(clientGrantsResponse)
   404  	case webIdentity:
   405  		webIdentityResponse := &AssumeRoleWithWebIdentityResponse{
   406  			Result: WebIdentityResult{
   407  				Credentials:                 cred,
   408  				SubjectFromWebIdentityToken: subFromToken,
   409  			},
   410  		}
   411  		webIdentityResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
   412  		encodedSuccessResponse = EncodeResponse(webIdentityResponse)
   413  	}
   414  
   415  	WriteSuccessResponseXML(w, encodedSuccessResponse)
   416  }
   417  
   418  // AssumeRoleWithWebIdentity - implementation of AWS STS API supporting OAuth2.0
   419  // users from web identity provider such as Facebook, Google, or any OpenID
   420  // Connect-compatible identity provider.
   421  //
   422  // Eg:-
   423  //    $ curl https://minio:9000/?Action=AssumeRoleWithWebIdentity&WebIdentityToken=<jwt>
   424  func (sts *stsAPIHandlers) AssumeRoleWithWebIdentity(w http.ResponseWriter, r *http.Request) {
   425  	sts.AssumeRoleWithSSO(w, r)
   426  }
   427  
   428  // AssumeRoleWithClientGrants - implementation of AWS STS extension API supporting
   429  // OAuth2.0 client credential grants.
   430  //
   431  // Eg:-
   432  //    $ curl https://minio:9000/?Action=AssumeRoleWithClientGrants&Token=<jwt>
   433  func (sts *stsAPIHandlers) AssumeRoleWithClientGrants(w http.ResponseWriter, r *http.Request) {
   434  	sts.AssumeRoleWithSSO(w, r)
   435  }
   436  
   437  // AssumeRoleWithLDAPIdentity - implements user auth against LDAP server
   438  func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *http.Request) {
   439  	ctx := NewContext(r, w, "AssumeRoleWithLDAPIdentity")
   440  
   441  	defer logger.AuditLog(ctx, w, r, nil, stsLDAPPassword)
   442  
   443  	// Parse the incoming form data.
   444  	if err := r.ParseForm(); err != nil {
   445  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   446  		return
   447  	}
   448  
   449  	if r.Form.Get(stsVersion) != stsAPIVersion {
   450  		writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter,
   451  			fmt.Errorf("Invalid STS API version %s, expecting %s", r.Form.Get("Version"), stsAPIVersion))
   452  		return
   453  	}
   454  
   455  	ldapUsername := r.Form.Get(stsLDAPUsername)
   456  	ldapPassword := r.Form.Get(stsLDAPPassword)
   457  
   458  	if ldapUsername == "" || ldapPassword == "" {
   459  		writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, fmt.Errorf("LDAPUsername and LDAPPassword cannot be empty"))
   460  		return
   461  	}
   462  
   463  	action := r.Form.Get(stsAction)
   464  	switch action {
   465  	case ldapIdentity:
   466  	default:
   467  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Unsupported action %s", action))
   468  		return
   469  	}
   470  
   471  	sessionPolicyStr := r.Form.Get(stsPolicy)
   472  	// https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
   473  	// The plain text that you use for both inline and managed session
   474  	// policies shouldn't exceed 2048 characters.
   475  	if len(sessionPolicyStr) > 2048 {
   476  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Session policy should not exceed 2048 characters"))
   477  		return
   478  	}
   479  
   480  	if len(sessionPolicyStr) > 0 {
   481  		sessionPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicyStr)))
   482  		if err != nil {
   483  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   484  			return
   485  		}
   486  
   487  		// Version in policy must not be empty
   488  		if sessionPolicy.Version == "" {
   489  			writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, fmt.Errorf("Version needs to be specified in session policy"))
   490  			return
   491  		}
   492  	}
   493  
   494  	ldapUserDN, groupDistNames, err := globalLDAPConfig.Bind(ldapUsername, ldapPassword)
   495  	if err != nil {
   496  		err = fmt.Errorf("LDAP server error: %w", err)
   497  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err)
   498  		return
   499  	}
   500  
   501  	// Check if this user or their groups have a policy applied.
   502  	ldapPolicies, _ := GlobalIAMSys.PolicyDBGet(ldapUserDN, false, groupDistNames...)
   503  	if len(ldapPolicies) == 0 {
   504  		writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
   505  			fmt.Errorf("expecting a policy to be set for user `%s` or one of their groups: `%s` - rejecting this request",
   506  				ldapUserDN, strings.Join(groupDistNames, "`,`")))
   507  		return
   508  	}
   509  
   510  	expiryDur := globalLDAPConfig.GetExpiryDuration()
   511  	m := map[string]interface{}{
   512  		expClaim: UTCNow().Add(expiryDur).Unix(),
   513  		ldapUser: ldapUserDN,
   514  	}
   515  
   516  	if len(sessionPolicyStr) > 0 {
   517  		m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString([]byte(sessionPolicyStr))
   518  	}
   519  
   520  	secret := globalActiveCred.SecretKey
   521  	cred, err := auth.GetNewCredentialsWithMetadata(m, secret)
   522  	if err != nil {
   523  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   524  		return
   525  	}
   526  
   527  	// Set the parent of the temporary access key, this is useful
   528  	// in obtaining service accounts by this cred.
   529  	cred.ParentUser = ldapUserDN
   530  
   531  	// Set this value to LDAP groups, LDAP user can be part
   532  	// of large number of groups
   533  	cred.Groups = groupDistNames
   534  
   535  	// Set the newly generated credentials, policyName is empty on purpose
   536  	// LDAP policies are applied automatically using their ldapUser, ldapGroups
   537  	// mapping.
   538  	if err = GlobalIAMSys.SetTempUser(cred.AccessKey, cred, ""); err != nil {
   539  		writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
   540  		return
   541  	}
   542  
   543  	// Notify all other MinIO peers to reload temp users
   544  	for _, nerr := range GlobalNotificationSys.LoadUser(cred.AccessKey, true) {
   545  		if nerr.Err != nil {
   546  			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
   547  			logger.LogIf(ctx, nerr.Err)
   548  		}
   549  	}
   550  
   551  	ldapIdentityResponse := &AssumeRoleWithLDAPResponse{
   552  		Result: LDAPIdentityResult{
   553  			Credentials: cred,
   554  		},
   555  	}
   556  	ldapIdentityResponse.ResponseMetadata.RequestID = w.Header().Get(xhttp.AmzRequestID)
   557  	encodedSuccessResponse := EncodeResponse(ldapIdentityResponse)
   558  
   559  	WriteSuccessResponseXML(w, encodedSuccessResponse)
   560  }