// This file is part of MinIO Console Server // Copyright (c) 2020 MinIO, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package auth import ( "context" "log" "github.com/minio/console/cluster" "github.com/minio/minio-go/v7/pkg/credentials" operatorClientset "github.com/minio/operator/pkg/client/clientset/versioned" ) // operatorCredentialsProvider is an struct to hold the JWT (service account token) type operatorCredentialsProvider struct { serviceAccountJWT string } // Implementing the interfaces of the minio Provider, we use this to leverage on the existing console Authentication flow func (s operatorCredentialsProvider) Retrieve() (credentials.Value, error) { return credentials.Value{ AccessKeyID: "", SecretAccessKey: "", SessionToken: s.serviceAccountJWT, }, nil } // IsExpired dummy function, must be implemented in order to work with the minio provider authentication func (s operatorCredentialsProvider) IsExpired() bool { return false } // OperatorClient interface with all functions to be implemented // by mock when testing, it should include all OperatorClient respective api calls // that are used within this project. type OperatorClient interface { Authenticate(context.Context) ([]byte, error) } // Interface implementation // // Define the structure of a operator client and define the functions that are actually used // from the minio operator. type operatorClient struct { client *operatorClientset.Clientset } // Authenticate implements the operator authenticate function via REST /api func (c *operatorClient) Authenticate(ctx context.Context) ([]byte, error) { return c.client.RESTClient().Verb("GET").RequestURI("/api").DoRaw(ctx) } // isServiceAccountTokenValid will make an authenticated request against kubernetes api, if the // request success means the provided jwt its a valid service account token and the console user can use it for future // requests until it expires func isServiceAccountTokenValid(ctx context.Context, operatorClient OperatorClient) bool { _, err := operatorClient.Authenticate(ctx) if err != nil { log.Println(err) return false } return true } // GetConsoleCredentialsForOperator will validate the provided JWT (service account token) and return it in the form of credentials.Login func GetConsoleCredentialsForOperator(jwt string) (*credentials.Credentials, error) { ctx := context.Background() opClientClientSet, err := cluster.OperatorClient(jwt) if err != nil { return nil, err } opClient := &operatorClient{ client: opClientClientSet, } if isServiceAccountTokenValid(ctx, opClient) { return credentials.New(operatorCredentialsProvider{serviceAccountJWT: jwt}), nil } return nil, errInvalidCredentials }