Skip to content

Commit

Permalink
Merge pull request #1169 from npamudika/master
Browse files Browse the repository at this point in the history
Add changes to support PAT
  • Loading branch information
npamudika authored May 30, 2024
2 parents 633bfb4 + 1a7ca67 commit 076794f
Show file tree
Hide file tree
Showing 15 changed files with 138 additions and 88 deletions.
1 change: 1 addition & 0 deletions import-export-cli/cmd/deprecated/listApiProducts.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func executeApiProductsCmd(credential credentials.Credential) {
impl.PrintAPIProducts(apiProducts, listApiProductsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of API Products", err)
utils.HandleErrorAndExit("Error getting the list of API Products.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/deprecated/listApis.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func executeApisCmd(credential credentials.Credential) {
impl.PrintAPIs(apis, listApisCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of APIs", err)
utils.HandleErrorAndExit("Error getting the list of APIs.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/deprecated/listApps.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func executeAppsCmd(credential credentials.Credential, appOwner string) {
impl.PrintApps(apps, listAppsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of Applications", err)
utils.HandleErrorAndExit("Error getting the list of Applications.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/getAPIProductRevisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func executeGetAPIProductRevisionsCmd(credential credentials.Credential) {
impl.PrintRevisions(revisions, getAPIProductRevisionsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of Revisions", err)
utils.HandleErrorAndExit("Error getting the list of revisions.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/getAPIRevisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func executeGetAPIRevisionsCmd(credential credentials.Credential) {
impl.PrintRevisions(revisions, getAPIRevisionsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of API Revisions", err)
utils.HandleErrorAndExit("Error getting the list of API revisions.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/getApiProducts.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func executeGetApiProductsCmd(credential credentials.Credential) {
impl.PrintAPIProducts(apiProducts, getApiProductsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of API Products", err)
utils.HandleErrorAndExit("Error getting the list of API Products.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/getApis.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func executeGetApisCmd(credential credentials.Credential) {
impl.PrintAPIs(apis, getApisCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of APIs", err)
utils.HandleErrorAndExit("Error getting the list of APIs.", err)
}
}

Expand Down
1 change: 1 addition & 0 deletions import-export-cli/cmd/getApps.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func executeGetAppsCmd(credential credentials.Credential, appOwner string) {
impl.PrintApps(apps, getAppsCmdFormat)
} else {
utils.Logln(utils.LogPrefixError+"Getting List of Applications", err)
utils.HandleErrorAndExit("Error getting the list of Applications.", err)
}
}

Expand Down
95 changes: 55 additions & 40 deletions import-export-cli/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ import (
var loginUsername string
var loginPassword string
var loginPasswordStdin bool
var clientId string
var clientSecret string
var personalAccessToken string

const loginCmdLiteral = "login [environment] [flags]"
const loginCmdShortDesc = "Login to an API Manager"
const loginCmdLongDesc = `Login to an API Manager using credentials`
const loginCmdLongDesc = `Login to an API Manager using credentials or set token for authentication`
const loginCmdExamples = utils.ProjectName + " login dev -u admin -p admin\n" +
utils.ProjectName + " login dev -u admin\n" +
"cat ~/.mypassword | " + utils.ProjectName + " login dev -u admin"
"cat ~/.mypassword | " + utils.ProjectName + " login dev -u admin\n" +
utils.ProjectName + " login dev --token e79bda48-3406-3178-acce-f6e4dbdcbb12"

// loginCmd represents the login command
var loginCmd = &cobra.Command{
Expand All @@ -52,58 +56,64 @@ var loginCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
environment := args[0]

if loginPassword != "" {
fmt.Println("Warning: Using --password in CLI is not secure. Use --password-stdin")
if loginPasswordStdin {
fmt.Println("--password and --password-stdin are mutual exclusive")
os.Exit(1)
}
store, err := credentials.GetDefaultCredentialStore()
if err != nil {
fmt.Println("Error occurred while loading credential store : ", err)
os.Exit(1)
}

if loginPasswordStdin {
if loginUsername == "" {
fmt.Println("An username is required to use password-stdin")
if personalAccessToken != "" {
err = runLogin(store, environment, loginUsername, loginPassword, personalAccessToken)
if err != nil {
fmt.Println("Error occurred while login using the token : ", err)
os.Exit(1)
}
} else {
if loginPassword != "" {
fmt.Println("Warning: Using --password in CLI is not secure. Use --password-stdin")
if loginPasswordStdin {
fmt.Println("--password and --password-stdin are mutual exclusive")
os.Exit(1)
}
}

data, err := ioutil.ReadAll(os.Stdin)
if loginPasswordStdin {
if loginUsername == "" {
fmt.Println("An username is required to use password-stdin")
os.Exit(1)
}

data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

loginPassword = strings.TrimRight(strings.TrimSuffix(string(data), "\n"), "\r")
}
err = runLogin(store, environment, loginUsername, loginPassword, personalAccessToken)
if err != nil {
fmt.Println(err)
fmt.Println("Error occurred while login : ", err)
os.Exit(1)
}

loginPassword = strings.TrimRight(strings.TrimSuffix(string(data), "\n"), "\r")
}

store, err := credentials.GetDefaultCredentialStore()
if err != nil {
fmt.Println("Error occurred while loading credential store : ", err)
os.Exit(1)
}
err = runLogin(store, environment, loginUsername, loginPassword)
if err != nil {
fmt.Println("Error occurred while login : ", err)
os.Exit(1)
}
},
}

func runLogin(store credentials.Store, environment, username, password string) error {
func runLogin(store credentials.Store, environment, username, password, personalAccessToken string) error {
if !utils.APIMExistsInEnv(environment, utils.MainConfigFilePath) {
fmt.Println("APIM does not exists in", environment, "Add it using add env")
os.Exit(1)
}

if username == "" {
if username == "" && personalAccessToken == "" {
fmt.Print("Username:")
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
username = scanner.Text()
}
}

if password == "" {
if password == "" && personalAccessToken == "" {
fmt.Print("Password:")
pass, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
Expand All @@ -113,22 +123,26 @@ func runLogin(store credentials.Store, environment, username, password string) e
fmt.Println()
}

registrationEndpoint := utils.GetRegistrationEndpointOfEnv(environment, utils.MainConfigFilePath)
clientId, clientSecret, err := utils.GetClientIDSecret(username, password, registrationEndpoint)
if err != nil {
return err
if username != "" && password != "" {
registrationEndpoint := utils.GetRegistrationEndpointOfEnv(environment, utils.MainConfigFilePath)
id, secret, err := utils.GetClientIDSecret(username, password, registrationEndpoint)
if err != nil {
return err
}
clientId = id
clientSecret = secret
}

fmt.Println("Logged into APIM in", environment, "environment")
err = store.SetAPIMCredentials(environment, username, password, clientId, clientSecret)
fmt.Println("Logged into APIM in ", environment, "environment")
err := store.SetAPIMCredentials(environment, username, password, clientId, clientSecret, personalAccessToken)
if err != nil {
return err
}

return nil
}

// GetCredentials functions get the credentials for the specified environment
// GetCredentials function gets the credentials for the specified environment
func GetCredentials(env string) (credentials.Credential, error) {
// get tokens or login
store, err := credentials.GetDefaultCredentialStore()
Expand All @@ -143,8 +157,8 @@ func GetCredentials(env string) (credentials.Credential, error) {

// check for creds
if !store.HasAPIM(env) {
fmt.Println("Login to APIM in", env)
err = runLogin(store, env, "", "")
fmt.Println("Login to APIM in ", env)
err = runLogin(store, env, "", "", "")
if err != nil {
return credentials.Credential{}, err
}
Expand All @@ -164,4 +178,5 @@ func init() {
loginCmd.Flags().StringVarP(&loginUsername, "username", "u", "", "Username for login")
loginCmd.Flags().StringVarP(&loginPassword, "password", "p", "", "Password for login")
loginCmd.Flags().BoolVarP(&loginPasswordStdin, "password-stdin", "", false, "Get password from stdin")
loginCmd.Flags().StringVarP(&personalAccessToken, "token", "", "", "Personal access token")
}
85 changes: 47 additions & 38 deletions import-export-cli/credentials/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Credential struct {
ClientId string `json:"clientId"`
// ClientSecret for cli
ClientSecret string `json:"clientSecret"`
// PersonalAccessToken of API Manager
PersonalAccessToken string `json:"accessToken"`
}

// Credentials of cli
Expand Down Expand Up @@ -83,15 +85,19 @@ func GetDefaultCredentialStore() (Store, error) {

// GetOAuthAccessToken generates an accesstoken for CLI
func GetOAuthAccessToken(credential Credential, env string) (string, error) {
tokenEndpoint := utils.GetInternalTokenEndpointOfEnv(env, utils.MainConfigFilePath)
data, err := utils.GetOAuthTokens(credential.Username, credential.Password,
Base64Encode(credential.ClientId+":"+credential.ClientSecret),
tokenEndpoint)
if err != nil {
return "", err
}
if accessToken, ok := data["access_token"]; ok {
return accessToken, nil
if credential.PersonalAccessToken != "" {
return credential.PersonalAccessToken, nil
} else {
tokenEndpoint := utils.GetInternalTokenEndpointOfEnv(env, utils.MainConfigFilePath)
data, err := utils.GetOAuthTokens(credential.Username, credential.Password,
Base64Encode(credential.ClientId+":"+credential.ClientSecret),
tokenEndpoint)
if err != nil {
return "", err
}
if accessToken, ok := data["access_token"]; ok {
return accessToken, nil
}
}
return "", errors.New("access_token not found")
}
Expand All @@ -101,35 +107,38 @@ func GetBasicAuth(credential Credential) string {
return Base64Encode(fmt.Sprintf("%s:%s", credential.Username, credential.Password))
}

//Revoke access Token when user is logging out from environment
// Revoke access Token when user is logging out from environment
func RevokeAccessToken(credential Credential, env string, token string) error {

//get revoke endpoint
tokenRevokeEndpoint := utils.GetTokenRevokeEndpoint(env, utils.MainConfigFilePath)
//Encoding client secret and client Id
var b64EncodedClientIDClientSecret = utils.GetBase64EncodedCredentials(credential.ClientId, credential.ClientSecret)
// set headers to request
headers := make(map[string]string)
headers[utils.HeaderContentType] = utils.HeaderValueXWWWFormUrlEncoded
headers[utils.HeaderAuthorization] = utils.HeaderValueAuthBasicPrefix + " " + b64EncodedClientIDClientSecret

//Create body for the request
body := utils.HeaderToken + token + utils.TokenTypeForRevocation

utils.Logln(utils.LogPrefixInfo + "connecting to " + tokenRevokeEndpoint)
resp, err := utils.InvokePOSTRequest(tokenRevokeEndpoint, headers, body)

if err != nil {
return err
}

//Check status code
if resp.StatusCode() != http.StatusOK {
return errors.New("Request didn't respond 200 OK for searching token revocation " +
"Status: " + resp.Status())
if credential.PersonalAccessToken != "" {
return nil
} else {
//get revoke endpoint
tokenRevokeEndpoint := utils.GetTokenRevokeEndpoint(env, utils.MainConfigFilePath)
//Encoding client secret and client Id
var b64EncodedClientIDClientSecret = utils.GetBase64EncodedCredentials(credential.ClientId, credential.ClientSecret)
// set headers to request
headers := make(map[string]string)
headers[utils.HeaderContentType] = utils.HeaderValueXWWWFormUrlEncoded
headers[utils.HeaderAuthorization] = utils.HeaderValueAuthBasicPrefix + " " + b64EncodedClientIDClientSecret

//Create body for the request
body := utils.HeaderToken + token + utils.TokenTypeForRevocation

utils.Logln(utils.LogPrefixInfo + "connecting to " + tokenRevokeEndpoint)
resp, err := utils.InvokePOSTRequest(tokenRevokeEndpoint, headers, body)

if err != nil {
return err
}

//Check status code
if resp.StatusCode() != http.StatusOK {
return errors.New("Request didn't respond 200 OK for searching token revocation " +
"Status: " + resp.Status())
}
responseDataMap := make(map[string]string) // a map to hold response data
data := []byte(resp.Body())
json.Unmarshal(data, &responseDataMap) // add response data to the map
return nil
}
responseDataMap := make(map[string]string) // a map to hold response data
data := []byte(resp.Body())
json.Unmarshal(data, &responseDataMap) // add response data to the map
return nil
}
26 changes: 18 additions & 8 deletions import-export-cli/credentials/jsonstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,27 @@ func (s *JsonStore) GetAPIMCredentials(env string) (Credential, error) {
if err != nil {
return Credential{}, err
}
personalAccessToken, err := Base64Decode(environment.APIM.PersonalAccessToken)
if err != nil {
return Credential{}, err
}
credential := Credential{
username, password, clientID, clientSecret,
username, password, clientID, clientSecret, personalAccessToken,
}
return credential, nil
}
return Credential{}, fmt.Errorf("credentials not found for APIM in %s, use login", env)
}

// SetAPIMCredentials sets credentials for micro integrator using username, password, clientID and client secret
func (s *JsonStore) SetAPIMCredentials(env, username, password, clientId, clientSecret string) error {
// SetAPIMCredentials sets credentials for apim using username, password, clientID, client secret and access token
func (s *JsonStore) SetAPIMCredentials(env, username, password, clientId, clientSecret, personalAccessToken string) error {
environment := s.credentials.Environments[env]
environment.APIM = Credential{
Username: Base64Encode(username),
Password: Base64Encode(password),
ClientId: Base64Encode(clientId),
ClientSecret: Base64Encode(clientSecret),
Username: Base64Encode(username),
Password: Base64Encode(password),
ClientId: Base64Encode(clientId),
ClientSecret: Base64Encode(clientSecret),
PersonalAccessToken: Base64Encode(personalAccessToken),
}
s.credentials.Environments[env] = environment
err := s.persist()
Expand Down Expand Up @@ -267,7 +272,12 @@ func miCredentialsExists(miCred MiCredential) bool {
}

func apimCredentialsExists(apimCred Credential) bool {
return apimCred.ClientId != "" && apimCred.ClientSecret != "" && apimCred.Username != "" && apimCred.Password != ""
if apimCred.ClientId != "" && apimCred.ClientSecret != "" && apimCred.Username != "" && apimCred.Password != "" {
return true
} else if apimCred.PersonalAccessToken != "" {
return true
}
return false
}

func mgTokenExists(mgwAdapterToken MgAdapterEnv) bool {
Expand Down
2 changes: 1 addition & 1 deletion import-export-cli/credentials/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type Store interface {
// GetMgwAdapterToken returns the Access Token of the Microgateway Adapter
GetMGToken(env string) (MgAdapterEnv, error)
// SetAPIMCredentials sets credentials for micro integrator using username, password, clientID and client secret
SetAPIMCredentials(env, username, password, clientID, clientSecret string) error
SetAPIMCredentials(env, username, password, clientID, clientSecret, accessToken string) error
// SetMICredentials sets credentials for micro integrator using username, password and access token
SetMICredentials(env, username, password, accessToken string) error
// SetMGToken sets the Access Token for a Microgateway Adapter env
Expand Down
Loading

0 comments on commit 076794f

Please sign in to comment.