github.com/minio/console@v1.3.0/api/service_accounts_handlers.go (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"time"
    24  
    25  	"github.com/go-openapi/runtime/middleware"
    26  	"github.com/minio/console/api/operations"
    27  	saApi "github.com/minio/console/api/operations/service_account"
    28  	userApi "github.com/minio/console/api/operations/user"
    29  	"github.com/minio/console/models"
    30  	"github.com/minio/console/pkg/utils"
    31  	"github.com/minio/madmin-go/v3"
    32  	iampolicy "github.com/minio/pkg/v2/policy"
    33  )
    34  
    35  func registerServiceAccountsHandlers(api *operations.ConsoleAPI) {
    36  	// Create Service Account
    37  	api.ServiceAccountCreateServiceAccountHandler = saApi.CreateServiceAccountHandlerFunc(func(params saApi.CreateServiceAccountParams, session *models.Principal) middleware.Responder {
    38  		creds, err := getCreateServiceAccountResponse(session, params)
    39  		if err != nil {
    40  			return saApi.NewCreateServiceAccountDefault(err.Code).WithPayload(err.APIError)
    41  		}
    42  		return saApi.NewCreateServiceAccountCreated().WithPayload(creds)
    43  	})
    44  	// Create User Service Account
    45  	api.UserCreateAUserServiceAccountHandler = userApi.CreateAUserServiceAccountHandlerFunc(func(params userApi.CreateAUserServiceAccountParams, session *models.Principal) middleware.Responder {
    46  		creds, err := getCreateAUserServiceAccountResponse(session, params)
    47  		if err != nil {
    48  			return saApi.NewCreateServiceAccountDefault(err.Code).WithPayload(err.APIError)
    49  		}
    50  		return userApi.NewCreateAUserServiceAccountCreated().WithPayload(creds)
    51  	})
    52  	// Create User Service Account
    53  	api.UserCreateServiceAccountCredentialsHandler = userApi.CreateServiceAccountCredentialsHandlerFunc(func(params userApi.CreateServiceAccountCredentialsParams, session *models.Principal) middleware.Responder {
    54  		creds, err := getCreateAUserServiceAccountCredsResponse(session, params)
    55  		if err != nil {
    56  			return saApi.NewCreateServiceAccountDefault(err.Code).WithPayload(err.APIError)
    57  		}
    58  		return userApi.NewCreateServiceAccountCredentialsCreated().WithPayload(creds)
    59  	})
    60  	api.ServiceAccountCreateServiceAccountCredsHandler = saApi.CreateServiceAccountCredsHandlerFunc(func(params saApi.CreateServiceAccountCredsParams, session *models.Principal) middleware.Responder {
    61  		creds, err := getCreateServiceAccountCredsResponse(session, params)
    62  		if err != nil {
    63  			return saApi.NewCreateServiceAccountDefault(err.Code).WithPayload(err.APIError)
    64  		}
    65  		return userApi.NewCreateServiceAccountCredentialsCreated().WithPayload(creds)
    66  	})
    67  	// List Service Accounts for User
    68  	api.ServiceAccountListUserServiceAccountsHandler = saApi.ListUserServiceAccountsHandlerFunc(func(params saApi.ListUserServiceAccountsParams, session *models.Principal) middleware.Responder {
    69  		ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
    70  		defer cancel()
    71  		serviceAccounts, err := getUserServiceAccountsResponse(ctx, session, "")
    72  		if err != nil {
    73  			return saApi.NewListUserServiceAccountsDefault(err.Code).WithPayload(err.APIError)
    74  		}
    75  		return saApi.NewListUserServiceAccountsOK().WithPayload(serviceAccounts)
    76  	})
    77  
    78  	// Delete a User's service account
    79  	api.ServiceAccountDeleteServiceAccountHandler = saApi.DeleteServiceAccountHandlerFunc(func(params saApi.DeleteServiceAccountParams, session *models.Principal) middleware.Responder {
    80  		if err := getDeleteServiceAccountResponse(session, params); err != nil {
    81  			return saApi.NewDeleteServiceAccountDefault(err.Code).WithPayload(err.APIError)
    82  		}
    83  		return saApi.NewDeleteServiceAccountNoContent()
    84  	})
    85  
    86  	// List Service Accounts for User
    87  	api.UserListAUserServiceAccountsHandler = userApi.ListAUserServiceAccountsHandlerFunc(func(params userApi.ListAUserServiceAccountsParams, session *models.Principal) middleware.Responder {
    88  		ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
    89  		defer cancel()
    90  		serviceAccounts, err := getUserServiceAccountsResponse(ctx, session, params.Name)
    91  		if err != nil {
    92  			return saApi.NewListUserServiceAccountsDefault(err.Code).WithPayload(err.APIError)
    93  		}
    94  		return saApi.NewListUserServiceAccountsOK().WithPayload(serviceAccounts)
    95  	})
    96  
    97  	api.ServiceAccountGetServiceAccountHandler = saApi.GetServiceAccountHandlerFunc(func(params saApi.GetServiceAccountParams, session *models.Principal) middleware.Responder {
    98  		serviceAccounts, err := getServiceAccountInfo(session, params)
    99  		if err != nil {
   100  			return saApi.NewGetServiceAccountDefault(err.Code).WithPayload(err.APIError)
   101  		}
   102  		return saApi.NewGetServiceAccountOK().WithPayload(serviceAccounts)
   103  	})
   104  
   105  	api.ServiceAccountUpdateServiceAccountHandler = saApi.UpdateServiceAccountHandlerFunc(func(params saApi.UpdateServiceAccountParams, session *models.Principal) middleware.Responder {
   106  		err := updateSetServiceAccountResponse(session, params)
   107  		if err != nil {
   108  			return saApi.NewUpdateServiceAccountDefault(err.Code).WithPayload(err.APIError)
   109  		}
   110  		return saApi.NewUpdateServiceAccountOK()
   111  	})
   112  
   113  	// Delete multiple service accounts
   114  	api.ServiceAccountDeleteMultipleServiceAccountsHandler = saApi.DeleteMultipleServiceAccountsHandlerFunc(func(params saApi.DeleteMultipleServiceAccountsParams, session *models.Principal) middleware.Responder {
   115  		if err := getDeleteMultipleServiceAccountsResponse(session, params); err != nil {
   116  			return saApi.NewDeleteMultipleServiceAccountsDefault(err.Code).WithPayload(err.APIError)
   117  		}
   118  		return saApi.NewDeleteMultipleServiceAccountsNoContent()
   119  	})
   120  }
   121  
   122  // createServiceAccount adds a service account to the userClient and assigns a policy to him if defined.
   123  func createServiceAccount(ctx context.Context, userClient MinioAdmin, policy string, name string, description string, expiry *time.Time, comment string) (*models.ServiceAccountCreds, error) {
   124  	creds, err := userClient.addServiceAccount(ctx, policy, "", "", "", name, description, expiry, comment)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return &models.ServiceAccountCreds{AccessKey: creds.AccessKey, SecretKey: creds.SecretKey, URL: getMinIOServer()}, nil
   129  }
   130  
   131  // createServiceAccount adds a service account with the given credentials to the
   132  // userClient and assigns a policy to him if defined.
   133  func createServiceAccountCreds(ctx context.Context, userClient MinioAdmin, policy string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (*models.ServiceAccountCreds, error) {
   134  	creds, err := userClient.addServiceAccount(ctx, policy, "", accessKey, secretKey, name, description, expiry, comment)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	return &models.ServiceAccountCreds{AccessKey: creds.AccessKey, SecretKey: creds.SecretKey, URL: getMinIOServer()}, nil
   139  }
   140  
   141  // getCreateServiceAccountResponse creates a service account with the defined policy for the user that
   142  // is requesting, it first gets the credentials of the user and creates a client which is going to
   143  // make the call to create the Service Account
   144  func getCreateServiceAccountResponse(session *models.Principal, params saApi.CreateServiceAccountParams) (*models.ServiceAccountCreds, *CodedAPIError) {
   145  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   146  	defer cancel()
   147  
   148  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   149  	if err != nil {
   150  		return nil, ErrorWithContext(ctx, err)
   151  	}
   152  	// create a MinIO user Admin Client interface implementation
   153  	// defining the client to be used
   154  	userAdminClient := AdminClient{Client: userAdmin}
   155  
   156  	var parsedExpiry time.Time
   157  	if params.Body.Expiry != "" {
   158  		parsedExpiry, err = time.Parse(time.RFC3339, params.Body.Expiry)
   159  		if err != nil {
   160  			return nil, ErrorWithContext(ctx, err)
   161  		}
   162  	}
   163  	saCreds, err := createServiceAccount(ctx, userAdminClient, params.Body.Policy, params.Body.Name, params.Body.Description, &parsedExpiry, params.Body.Comment)
   164  	if err != nil {
   165  		return nil, ErrorWithContext(ctx, err)
   166  	}
   167  	return saCreds, nil
   168  }
   169  
   170  // createServiceAccount adds a service account to a given user and assigns a policy to him if defined.
   171  func createAUserServiceAccount(ctx context.Context, userClient MinioAdmin, policy string, user string, name string, description string, expiry *time.Time, comment string) (*models.ServiceAccountCreds, error) {
   172  	creds, err := userClient.addServiceAccount(ctx, policy, user, "", "", name, description, expiry, comment)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	return &models.ServiceAccountCreds{AccessKey: creds.AccessKey, SecretKey: creds.SecretKey, URL: getMinIOServer()}, nil
   177  }
   178  
   179  func createAUserServiceAccountCreds(ctx context.Context, userClient MinioAdmin, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (*models.ServiceAccountCreds, error) {
   180  	creds, err := userClient.addServiceAccount(ctx, policy, user, accessKey, secretKey, name, description, expiry, comment)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	return &models.ServiceAccountCreds{AccessKey: creds.AccessKey, SecretKey: creds.SecretKey, URL: getMinIOServer()}, nil
   185  }
   186  
   187  // getCreateServiceAccountResponse creates a service account with the defined policy for the user that
   188  // is requesting it ,it first gets the credentials of the user and creates a client which is going to
   189  // make the call to create the Service Account
   190  func getCreateAUserServiceAccountResponse(session *models.Principal, params userApi.CreateAUserServiceAccountParams) (*models.ServiceAccountCreds, *CodedAPIError) {
   191  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   192  	defer cancel()
   193  
   194  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   195  	if err != nil {
   196  		return nil, ErrorWithContext(ctx, err)
   197  	}
   198  	// create a MinIO user Admin Client interface implementation
   199  	// defining the client to be used
   200  	userAdminClient := AdminClient{Client: userAdmin}
   201  	name, err := utils.DecodeBase64(params.Name)
   202  	if err != nil {
   203  		return nil, ErrorWithContext(ctx, err)
   204  	}
   205  
   206  	var parsedExpiry time.Time
   207  	if params.Body.Expiry != "" {
   208  		parsedExpiry, err = time.Parse(time.RFC3339, params.Body.Expiry)
   209  		if err != nil {
   210  			return nil, ErrorWithContext(ctx, err)
   211  		}
   212  	}
   213  	saCreds, err := createAUserServiceAccount(ctx, userAdminClient, params.Body.Policy, name, params.Body.Name, params.Body.Description, &parsedExpiry, params.Body.Comment)
   214  	if err != nil {
   215  		return nil, ErrorWithContext(ctx, err)
   216  	}
   217  	return saCreds, nil
   218  }
   219  
   220  // getCreateServiceAccountCredsResponse creates a service account with the defined policy for the user that
   221  // is requesting it, and with the credentials provided
   222  func getCreateAUserServiceAccountCredsResponse(session *models.Principal, params userApi.CreateServiceAccountCredentialsParams) (*models.ServiceAccountCreds, *CodedAPIError) {
   223  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   224  	defer cancel()
   225  
   226  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   227  	if err != nil {
   228  		return nil, ErrorWithContext(ctx, err)
   229  	}
   230  	// create a MinIO user Admin Client interface implementation
   231  	// defining the client to be used
   232  	userAdminClient := AdminClient{Client: userAdmin}
   233  	serviceAccount := params.Body
   234  	user, err := utils.DecodeBase64(params.Name)
   235  	if err != nil {
   236  		return nil, ErrorWithContext(ctx, err)
   237  	}
   238  	if user == serviceAccount.AccessKey {
   239  		return nil, ErrorWithContext(ctx, errors.New("Access Key already in use"))
   240  	}
   241  	accounts, err := userAdminClient.listServiceAccounts(ctx, user)
   242  	if err != nil {
   243  		return nil, ErrorWithContext(ctx, err)
   244  	}
   245  	for i := 0; i < len(accounts.Accounts); i++ {
   246  		if accounts.Accounts[i].AccessKey == serviceAccount.AccessKey {
   247  			return nil, ErrorWithContext(ctx, errors.New("Access Key already in use"))
   248  		}
   249  	}
   250  
   251  	var parsedExpiry time.Time
   252  	if serviceAccount.Expiry != "" {
   253  		parsedExpiry, err = time.Parse(time.RFC3339, serviceAccount.Expiry)
   254  		if err != nil {
   255  			return nil, ErrorWithContext(ctx, err)
   256  		}
   257  	}
   258  	saCreds, err := createAUserServiceAccountCreds(ctx, userAdminClient, serviceAccount.Policy, user, serviceAccount.AccessKey, serviceAccount.SecretKey, serviceAccount.Name, serviceAccount.Description, &parsedExpiry, serviceAccount.Comment)
   259  	if err != nil {
   260  		return nil, ErrorWithContext(ctx, err)
   261  	}
   262  	return saCreds, nil
   263  }
   264  
   265  func getCreateServiceAccountCredsResponse(session *models.Principal, params saApi.CreateServiceAccountCredsParams) (*models.ServiceAccountCreds, *CodedAPIError) {
   266  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   267  	defer cancel()
   268  	serviceAccount := params.Body
   269  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   270  	if err != nil {
   271  		return nil, ErrorWithContext(ctx, err)
   272  	}
   273  	// create a MinIO user Admin Client interface implementation
   274  	// defining the client to be used
   275  	userAdminClient := AdminClient{Client: userAdmin}
   276  
   277  	if session.AccountAccessKey == serviceAccount.AccessKey {
   278  		return nil, ErrorWithContext(ctx, errors.New("Access Key already in use"))
   279  	}
   280  
   281  	accounts, err := userAdminClient.listServiceAccounts(ctx, "")
   282  	if err != nil {
   283  		return nil, ErrorWithContext(ctx, err)
   284  	}
   285  
   286  	for i := 0; i < len(accounts.Accounts); i++ {
   287  		if accounts.Accounts[i].AccessKey == serviceAccount.AccessKey {
   288  			return nil, ErrorWithContext(ctx, errors.New("Access Key already in use"))
   289  		}
   290  	}
   291  
   292  	var parsedExpiry time.Time
   293  	if params.Body.Expiry != "" {
   294  		parsedExpiry, err = time.Parse(time.RFC3339, params.Body.Expiry)
   295  		if err != nil {
   296  			return nil, ErrorWithContext(ctx, err)
   297  		}
   298  	}
   299  
   300  	saCreds, err := createServiceAccountCreds(ctx, userAdminClient, serviceAccount.Policy, serviceAccount.AccessKey, serviceAccount.SecretKey, params.Body.Name, params.Body.Description, &parsedExpiry, params.Body.Comment)
   301  	if err != nil {
   302  		return nil, ErrorWithContext(ctx, err)
   303  	}
   304  	return saCreds, nil
   305  }
   306  
   307  // getUserServiceAccount gets list of the user's service accounts
   308  func getUserServiceAccounts(ctx context.Context, userClient MinioAdmin, user string) (models.ServiceAccounts, error) {
   309  	listServAccs, err := userClient.listServiceAccounts(ctx, user)
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  	saList := models.ServiceAccounts{}
   314  
   315  	for _, acc := range listServAccs.Accounts {
   316  		aInfo, err := userClient.infoServiceAccount(ctx, acc.AccessKey)
   317  		if err != nil {
   318  			continue
   319  		}
   320  		expiry := ""
   321  		if aInfo.Expiration != nil {
   322  			expiry = aInfo.Expiration.Format(time.RFC3339)
   323  		}
   324  
   325  		saList = append(saList, &models.ServiceAccountsItems0{
   326  			AccountStatus: aInfo.AccountStatus,
   327  			Description:   aInfo.Description,
   328  			Expiration:    expiry,
   329  			Name:          aInfo.Name,
   330  			AccessKey:     acc.AccessKey,
   331  		})
   332  	}
   333  	return saList, nil
   334  }
   335  
   336  // getUserServiceAccountsResponse authenticates the user and calls
   337  // getUserServiceAccounts to list the user's service accounts
   338  func getUserServiceAccountsResponse(ctx context.Context, session *models.Principal, user string) (models.ServiceAccounts, *CodedAPIError) {
   339  	userAdmin, err := NewMinioAdminClient(ctx, session)
   340  	if err != nil {
   341  		return nil, ErrorWithContext(ctx, err)
   342  	}
   343  	// create a MinIO user Admin Client interface implementation
   344  	// defining the client to be used
   345  	userAdminClient := AdminClient{Client: userAdmin}
   346  	user, err = utils.DecodeBase64(user)
   347  	if err != nil {
   348  		return nil, ErrorWithContext(ctx, err)
   349  	}
   350  	serviceAccounts, err := getUserServiceAccounts(ctx, userAdminClient, user)
   351  	if err != nil {
   352  		return nil, ErrorWithContext(ctx, err)
   353  	}
   354  	return serviceAccounts, nil
   355  }
   356  
   357  // deleteServiceAccount calls delete service account api
   358  func deleteServiceAccount(ctx context.Context, userClient MinioAdmin, accessKey string) error {
   359  	return userClient.deleteServiceAccount(ctx, accessKey)
   360  }
   361  
   362  // getDeleteServiceAccountResponse authenticates the user and calls deleteServiceAccount
   363  func getDeleteServiceAccountResponse(session *models.Principal, params saApi.DeleteServiceAccountParams) *CodedAPIError {
   364  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   365  	defer cancel()
   366  	accessKey, err := utils.DecodeBase64(params.AccessKey)
   367  	if err != nil {
   368  		return ErrorWithContext(ctx, err)
   369  	}
   370  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   371  	if err != nil {
   372  		return ErrorWithContext(ctx, err)
   373  	}
   374  	// create a MinIO user Admin Client interface implementation
   375  	// defining the client to be used
   376  	userAdminClient := AdminClient{Client: userAdmin}
   377  	if err := deleteServiceAccount(ctx, userAdminClient, accessKey); err != nil {
   378  		return ErrorWithContext(ctx, err)
   379  	}
   380  	return nil
   381  }
   382  
   383  // getServiceAccountDetails gets policy for a service account
   384  func getServiceAccountDetails(ctx context.Context, userClient MinioAdmin, accessKey string) (*models.ServiceAccount, error) {
   385  	saInfo, err := userClient.infoServiceAccount(ctx, accessKey)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	var policyJSON string
   391  	var policy iampolicy.Policy
   392  	json.Unmarshal([]byte(saInfo.Policy), &policy)
   393  	if policy.Statements == nil {
   394  		policyJSON = ""
   395  	} else {
   396  		policyJSON = saInfo.Policy
   397  	}
   398  
   399  	expiry := ""
   400  	if saInfo.Expiration != nil {
   401  		expiry = saInfo.Expiration.Format(time.RFC3339)
   402  	}
   403  
   404  	sa := models.ServiceAccount{
   405  		AccountStatus: saInfo.AccountStatus,
   406  		Description:   saInfo.Description,
   407  		Expiration:    expiry,
   408  		ImpliedPolicy: saInfo.ImpliedPolicy,
   409  		Name:          saInfo.Name,
   410  		ParentUser:    saInfo.ParentUser,
   411  		Policy:        policyJSON,
   412  	}
   413  	return &sa, nil
   414  }
   415  
   416  // getServiceAccountInfo authenticates the user and calls
   417  // getServiceAccountInfo to get the policy for a service account
   418  func getServiceAccountInfo(session *models.Principal, params saApi.GetServiceAccountParams) (*models.ServiceAccount, *CodedAPIError) {
   419  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   420  	defer cancel()
   421  	accessKey, err := utils.DecodeBase64(params.AccessKey)
   422  	if err != nil {
   423  		return nil, ErrorWithContext(ctx, err)
   424  	}
   425  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   426  	if err != nil {
   427  		return nil, ErrorWithContext(ctx, err)
   428  	}
   429  	// create a MinIO user Admin Client interface implementation
   430  	// defining the client to be used
   431  	userAdminClient := AdminClient{Client: userAdmin}
   432  
   433  	serviceAccount, err := getServiceAccountDetails(ctx, userAdminClient, accessKey)
   434  	if err != nil {
   435  		return nil, ErrorWithContext(ctx, err)
   436  	}
   437  
   438  	return serviceAccount, nil
   439  }
   440  
   441  // setServiceAccountPolicy sets policy for a service account
   442  func updateServiceAccountDetails(ctx context.Context, userClient MinioAdmin, accessKey string, policy string, expiry time.Time, name string, description string, status string, secretKey string) error {
   443  	req := madmin.UpdateServiceAccountReq{
   444  		NewPolicy:      json.RawMessage(policy),
   445  		NewSecretKey:   secretKey,
   446  		NewStatus:      status,
   447  		NewName:        name,
   448  		NewDescription: description,
   449  		NewExpiration:  &expiry,
   450  	}
   451  
   452  	err := userClient.updateServiceAccount(ctx, accessKey, req)
   453  	return err
   454  }
   455  
   456  // updateSetServiceAccountResponse authenticates the user and calls
   457  // getSetServiceAccountPolicy to set the policy for a service account
   458  func updateSetServiceAccountResponse(session *models.Principal, params saApi.UpdateServiceAccountParams) *CodedAPIError {
   459  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   460  	defer cancel()
   461  	accessKey, err := utils.DecodeBase64(params.AccessKey)
   462  	if err != nil {
   463  		return ErrorWithContext(ctx, err)
   464  	}
   465  	policy := *params.Body.Policy
   466  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   467  	if err != nil {
   468  		return ErrorWithContext(ctx, err)
   469  	}
   470  	// create a MinIO user Admin Client interface implementation
   471  	// defining the client to be used
   472  	userAdminClient := AdminClient{Client: userAdmin}
   473  
   474  	var parsedExpiry time.Time
   475  	if params.Body.Expiry != "" {
   476  		parsedExpiry, err = time.Parse(time.RFC3339, params.Body.Expiry)
   477  		if err != nil {
   478  			return ErrorWithContext(ctx, err)
   479  		}
   480  	}
   481  	err = updateServiceAccountDetails(ctx, userAdminClient, accessKey, policy, parsedExpiry, params.Body.Name, params.Body.Description, params.Body.Status, params.Body.SecretKey)
   482  	if err != nil {
   483  		return ErrorWithContext(ctx, err)
   484  	}
   485  	return nil
   486  }
   487  
   488  // getDeleteMultipleServiceAccountsResponse authenticates the user and calls deleteServiceAccount for each account listed in selectedSAs
   489  func getDeleteMultipleServiceAccountsResponse(session *models.Principal, params saApi.DeleteMultipleServiceAccountsParams) *CodedAPIError {
   490  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   491  	defer cancel()
   492  	selectedSAs := params.SelectedSA
   493  	userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   494  	if err != nil {
   495  		return ErrorWithContext(ctx, err)
   496  	}
   497  	// create a MinIO user Admin Client interface implementation
   498  	// defining the client to be used
   499  	userAdminClient := AdminClient{Client: userAdmin}
   500  	for _, sa := range selectedSAs {
   501  		if err := deleteServiceAccount(ctx, userAdminClient, sa); err != nil {
   502  			return ErrorWithContext(ctx, err)
   503  		}
   504  	}
   505  	return nil
   506  }