Skip to content

Commit

Permalink
Merge pull request portworx#136 from lpabon/tokengen
Browse files Browse the repository at this point in the history
Credentials token and whoami handlers
  • Loading branch information
lpabon committed Mar 27, 2020
2 parents 17766dc + 6c9643e commit 2d1db31
Show file tree
Hide file tree
Showing 8 changed files with 818 additions and 0 deletions.
43 changes: 43 additions & 0 deletions handler/config/credentials_token.go
@@ -0,0 +1,43 @@
/*
Copyright © 2020 Portworx
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package configcli

import (
"github.com/portworx/pxc/pkg/commander"
"github.com/portworx/pxc/pkg/util"
"github.com/spf13/cobra"
)

// tokenCmd represents the token command
var tokenCmd *cobra.Command

var _ = commander.RegisterCommandVar(func() {
tokenCmd = &cobra.Command{
Use: "token",
Short: "Portworx token management commands",
Run: func(cmd *cobra.Command, args []string) {
util.Printf("Please see pxc config credentials token --help for more commands\n")
},
}
})

var _ = commander.RegisterCommandInit(func() {
CredentialsAddCommand(tokenCmd)
})

func CredentialsTokenAddCommand(cmd *cobra.Command) {
tokenCmd.AddCommand(cmd)
}
118 changes: 118 additions & 0 deletions handler/config/credentials_whoami.go
@@ -0,0 +1,118 @@
/*
Copyright © 2020 Portworx
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package configcli

import (
"fmt"
"strings"
"time"

"github.com/portworx/pxc/pkg/auth"
"github.com/portworx/pxc/pkg/commander"
"github.com/portworx/pxc/pkg/config"
"github.com/portworx/pxc/pkg/portworx"
"github.com/portworx/pxc/pkg/util"
"github.com/spf13/cobra"
)

type whoamiOptions struct {
token string
}

var (
whoamiArgs *whoamiOptions
whoamiCmd *cobra.Command
)

var _ = commander.RegisterCommandVar(func() {
whoamiArgs = &whoamiOptions{}
whoamiCmd = &cobra.Command{
Use: "whoami",
Short: "Shows current authentication information",
RunE: whoAmIExec,
}
})

var _ = commander.RegisterCommandInit(func() {
CredentialsAddCommand(whoamiCmd)
whoamiCmd.Flags().StringVar(&whoamiArgs.token,
"auth-token", "", "Use this token instead of the token saved in the configuration. Useful for debugging tokens")
})

func WhoAmIAddCommand(cmd *cobra.Command) {
whoamiCmd.AddCommand(cmd)
}

func whoAmIExec(cmd *cobra.Command, args []string) error {
token := whoamiArgs.token
if len(token) == 0 {
authInfo := config.CM().GetCurrentAuthInfo()
token = authInfo.Token

if len(authInfo.KubernetesAuthInfo.SecretName) != 0 &&
len(authInfo.KubernetesAuthInfo.SecretNamespace) != 0 {
var err error
token, err = portworx.PxGetTokenFromSecret(authInfo.KubernetesAuthInfo.SecretName, authInfo.KubernetesAuthInfo.SecretNamespace)
if err != nil {
return fmt.Errorf("Unable to retreive token from Kubernetes: %v", err)
}
}
if len(token) == 0 {
util.Printf("No authentication information provided")
return nil
}
}

expTime, err := auth.GetExpiration(token)
if err != nil {
return fmt.Errorf("Unable to get expiration information from token: %v", err)
}
iatTime, err := auth.GetIssuedAtTime(token)
if err != nil {
return fmt.Errorf("Unable to get issued time information from token: %v", err)
}
claims, err := auth.TokenClaims(token)
if err != nil {
return err
}

status := "Ok"
err = auth.ValidateToken(token)
if err != nil {
status = fmt.Sprintf("%v", err)
}

util.Printf("Name: %s\n"+
"Email: %s\n"+
"Subject: %s\n"+
"Groups: %s\n"+
"Roles: %s\n"+
"Issued At Time: %s\n"+
"Expiration Time: %s\n"+
"\n"+
"Status: %s\n",
claims.Name,
claims.Email,
claims.Subject,
strings.Join(claims.Groups, ","),
strings.Join(claims.Roles, ","),
iatTime.Format(time.UnixDate),
expTime.Format(time.UnixDate),
status)

return nil

}
160 changes: 160 additions & 0 deletions handler/config/token_generate.go
@@ -0,0 +1,160 @@
/*
Copyright © 2020 Portworx
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package configcli

import (
"fmt"
"strings"
"time"

"github.com/portworx/pxc/pkg/auth"
"github.com/portworx/pxc/pkg/commander"
"github.com/portworx/pxc/pkg/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

type tokenInfo struct {
issuer string
subject string
name string
email string
roles string
groups string
}

type tokenGenOptions struct {
sharedSecret string
rsaPem string
ecdsaPem string
duration string
output string
token tokenInfo
}

// tokenGenCmd represents the tokenGen command
var (
tokenGenArgs *tokenGenOptions
tokenGenCmd *cobra.Command
)

var _ = commander.RegisterCommandVar(func() {
tokenGenArgs = &tokenGenOptions{}
tokenGenCmd = &cobra.Command{
Use: "generate",
Aliases: []string{"gen"},
Short: "Generate a Portworx token",
RunE: tokenGenExec,
}
})

var _ = commander.RegisterCommandInit(func() {
CredentialsTokenAddCommand(tokenGenCmd)
tokenGenCmd.Flags().StringVar(&tokenGenArgs.sharedSecret,
"shared-secret", "", "Shared secret to sign token")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.rsaPem,
"rsa-private-keyfile", "", "RSA Private file to sign token")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.ecdsaPem,
"ecdsa-private-keyfile", "", "ECDSA Private file to sign token")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.duration,
"token-duration", "1d", "Duration of time where the token will be valid. "+
"Postfix the duration by using "+
auth.SecondDef+" for seconds, "+
auth.MinuteDef+" for minutes, "+
auth.HourDef+" for hours, "+
auth.DayDef+" for days, and "+
auth.YearDef+" for years.")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.issuer,
"token-issuer", "portworx.com",
"Issuer name of token. Do not use https:// in the issuer since it could indicate "+
"that this is an OpenID Connect issuer.")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.name,
"token-name", "", "Account name")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.subject,
"token-subject", "", "Unique ID of this account")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.email,
"token-email", "", "Unique ID of this account")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.roles,
"token-roles", "", "Comma separated list of roles applied to this token")
tokenGenCmd.Flags().StringVar(&tokenGenArgs.token.groups,
"token-groups", "", "Comma separated list of groups which the token will be part of")

})

func TokenGenerateAddCommand(cmd *cobra.Command) {
tokenGenCmd.AddCommand(cmd)
}

func tokenGenExec(cmd *cobra.Command, args []string) error {

if len(tokenGenArgs.token.name) == 0 {
return fmt.Errorf("Must supply an account name")
} else if len(tokenGenArgs.token.email) == 0 {
return fmt.Errorf("Must supply an email address")
} else if len(tokenGenArgs.token.subject) == 0 {
return fmt.Errorf("Must supply a unique identifier as the subject")
}
if len(tokenGenArgs.token.roles) == 0 {
logrus.Warningf("Warning: No role provided")
}
if len(tokenGenArgs.token.groups) == 0 {
logrus.Warningf("Warning: No role provided")
}

claims := &auth.Claims{
Name: tokenGenArgs.token.name,
Email: tokenGenArgs.token.email,
Subject: tokenGenArgs.token.subject,
Roles: strings.Split(tokenGenArgs.token.roles, ","),
Groups: strings.Split(tokenGenArgs.token.groups, ","),
}

// Get duration
options := &auth.Options{
Issuer: tokenGenArgs.token.issuer,
}
expDuration, err := auth.ParseToDuration(tokenGenArgs.duration)
if err != nil {
return fmt.Errorf("Unable to parse duration")
}
options.Expiration = time.Now().Add(expDuration).Unix()

// Get signature
var signature *auth.Signature
if len(tokenGenArgs.sharedSecret) != 0 {
signature, err = auth.NewSignatureSharedSecret(tokenGenArgs.sharedSecret)
} else if len(tokenGenArgs.rsaPem) != 0 {
signature, err = auth.NewSignatureRSAFromFile(tokenGenArgs.rsaPem)
} else if len(tokenGenArgs.ecdsaPem) != 0 {
signature, err = auth.NewSignatureECDSAFromFile(tokenGenArgs.ecdsaPem)
} else {
return fmt.Errorf("Must provide a secret key to sign token")
}
if err != nil {
return fmt.Errorf("Unable to generate signature: %v", err)
}

// Generate token
token, err := auth.Token(claims, signature, options)
if err != nil {
return fmt.Errorf("Failed to create token: %v", err)
}

// Print token
util.Printf("%s\n", token)

return nil
}

0 comments on commit 2d1db31

Please sign in to comment.