Skip to content

Commit 306e0a8

Browse files
committed
Incorporate review feedback on token create tool
1 parent c5b094a commit 306e0a8

3 files changed

Lines changed: 33 additions & 22 deletions

File tree

cmd/origin_token.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func parseInputSlice(rawSlice *[]string, claimPrefix string) []string {
4646
}
4747

4848
// Parse claims to tokenConfig, excluding "sub". `claims` should be in the form of
49-
// <claim_key>=<claim=value>
49+
// <claim_key>=<claim_value>
5050
func parseClaimsToTokenConfig(profile string, claims []string) (*token.TokenConfig, error) {
5151
tokenProfile, err := token.ParseProfile(profile)
5252
if err != nil {

cmd/token.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ var (
5353
Short: "Create a token",
5454
RunE: createToken,
5555
Args: cobra.ExactArgs(1),
56+
Example: "To create a read/write token for /some/namespace/path in OSDF: " +
57+
"pelican token create --read --write pelican://osg-htc.org/some/namespace/path",
5658
}
5759
)
5860

@@ -65,17 +67,18 @@ func init() {
6567
"Does not grant the ability to overwrite/modify existing resources")
6668
tokenCreateCmd.Flags().BoolP("modify", "m", false, "Create a token with the ability to modify/delete the specified resource.")
6769
tokenCreateCmd.Flags().BoolP("stage", "s", false, "Create a token with the ability to stage the specified resource.")
68-
tokenCreateCmd.Flags().StringP("scope-path", "P", "", "Specify the path to use when creating the token's scopes. This should generally be "+
70+
tokenCreateCmd.Flags().String("scope-path", "", "Specify the path to use when creating the token's scopes. This should generally be "+
6971
"the object path without the namespace prefix.")
7072

7173
// Additional token fields
7274
tokenCreateCmd.Flags().StringP("audience", "a", "", "Specify the tokens audience. If not provided, the equivalent 'any' audience "+
7375
"for the selected profile will be used (e.g. 'https://wlcg.cern.ch/jwt/v1/any' for the 'wlcg' profile).")
7476
tokenCreateCmd.Flags().IntP("lifetime", "l", 1200, "Set the lifetime of the token in seconds. Default is 1200 (20min).")
75-
tokenCreateCmd.Flags().StringP("subject", "u", "", "Set the subject of the token. If not provided, the current user will be used as the default subject.")
77+
tokenCreateCmd.Flags().String("subject", "", "Set the subject of the token. If not provided, the current user will be used as the default subject.")
7678
tokenCreateCmd.Flags().StringP("issuer", "i", "", "Set the issuer of the token. If not provided, the issuer will be discovered via the Director.")
77-
tokenCreateCmd.Flags().StringArrayP("claim", "c", []string{}, "Set claims to be added to the token. Format: <claim_key>=<claim_value>. ")
78-
tokenCreateCmd.Flags().StringArrayP("scope", "C", []string{}, "Set non-typical values for the token's 'scope' claim. Format: <scope_key>=<scope_value>. ")
79+
tokenCreateCmd.Flags().StringArray("raw-claim", []string{}, "Set claims to be added to the token. Format: <claim_key>=<claim_value>. ")
80+
tokenCreateCmd.Flags().StringArray("raw-scope", []string{}, "Set non-typical values for the token's 'scope' claim. Scopes should be space-separated, e.g. "+
81+
"'storage.read:/ storage.create:/'.")
7982
tokenCreateCmd.Flags().StringP("profile", "p", "wlcg", "Create a token with a specific JWT profile. Accepted values are scitokens2 and wlcg")
8083
tokenCreateCmd.Flags().StringP("private-key", "k", "", "Path to the private key used to sign the token. If not provided, Pelican will look for the private key in the default location.")
8184
}
@@ -101,11 +104,9 @@ func verifyIssuer(issuer string, kidSet map[string]struct{}) (bool, error) {
101104
return false, err
102105
}
103106

104-
it := (*remoteJWKS).Keys(context.Background())
105-
for it.Next(context.Background()) {
106-
key := it.Pair().Value.(jwk.Key)
107-
if _, ok := kidSet[key.KeyID()]; ok {
108-
log.Debugf("Found matching key ID %s in JWKS from issuer %s", key.KeyID(), issuer)
107+
for kid := range kidSet {
108+
if _, ok := (*remoteJWKS).LookupKeyID(kid); ok {
109+
log.Debugf("Found matching key ID %s in JWKS from issuer %s", kid, issuer)
109110
return true, nil
110111
}
111112
}
@@ -120,7 +121,7 @@ func verifyIssuer(issuer string, kidSet map[string]struct{}) (bool, error) {
120121
// which issuer aligns with their signing key.
121122
func getIssuer(directorInfo server_structs.DirectorResponse, kidSet map[string]struct{}) (string, error) {
122123
if len(directorInfo.XPelAuthHdr.Issuers) == 0 {
123-
return "", errors.New("no issuers found for %s in the Director response")
124+
return "", errors.Errorf("no issuers found for %s in the Director response", directorInfo.XPelNsHdr.Namespace)
124125
}
125126

126127
// Comb through the JWKS from each issuer to find which matches the signing key
@@ -180,7 +181,8 @@ func createToken(cmd *cobra.Command, args []string) error {
180181
// First arg contains the pelican URL of the resource
181182
// Cobra has already checked that we have exactly one arg
182183
rawUrl := args[0]
183-
ctx := context.Background()
184+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
185+
defer cancel()
184186
pUrl, pUrlErr := client.ParseRemoteAsPUrl(ctx, rawUrl)
185187
sPath, err := cmd.Flags().GetString("scope-path")
186188
if err != nil {

config/init_server_creds.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -748,18 +748,21 @@ func loadIssuerPrivateKey(issuerKeysDir string) (jwk.Key, error) {
748748

749749
// Helper function to load the issuer/server's public key for other servers
750750
// to verify the token signed by this server. Only intended to be called internally
751-
func loadIssuerPublicJWKS(existingJWKS string, issuerKeysDir string, pemPath ...string) (jwk.Set, error) {
751+
//
752+
// The `keyPathOverridePEM` parameter is used to override the default locations by
753+
// providing a PEM file path.
754+
func loadIssuerPublicJWKS(existingJWKS string, issuerKeysDir string, keyPathOverridePEM ...string) (jwk.Set, error) {
752755
jwks := jwk.NewSet()
753756
if existingJWKS != "" {
754757
var err error
755758
jwks, err = jwk.ReadFile(existingJWKS)
756759
if err != nil {
757760
return nil, errors.Wrap(err, "Failed to read issuer JWKS file")
758761
}
759-
} else if len(pemPath) > 0 && pemPath[0] != "" {
760-
key, err := LoadSinglePEM(pemPath[0])
762+
} else if len(keyPathOverridePEM) > 0 && keyPathOverridePEM[0] != "" {
763+
key, err := LoadSinglePEM(keyPathOverridePEM[0])
761764
if err != nil {
762-
return nil, errors.Wrapf(err, "failed to load signing key from %s", pemPath[0])
765+
return nil, errors.Wrapf(err, "failed to load signing key from %s", keyPathOverridePEM[0])
763766
}
764767
pkey, err := jwk.PublicKeyOf(key)
765768
if err != nil {
@@ -798,12 +801,15 @@ func loadIssuerPublicJWKS(existingJWKS string, issuerKeysDir string, pemPath ...
798801
}
799802

800803
// Return the private JWK for the server to sign tokens and payloads
801-
func GetIssuerPrivateJWK(signingKey ...string) (jwk.Key, error) {
804+
//
805+
// The `keyPathOverridePEM` parameter is used to override the default locations by
806+
// providing a PEM file path.
807+
func GetIssuerPrivateJWK(keyPathOverridePEM ...string) (jwk.Key, error) {
802808
// If an optional key is provided, load it and return
803-
if len(signingKey) > 0 && signingKey[0] != "" {
804-
key, err := LoadSinglePEM(signingKey[0])
809+
if len(keyPathOverridePEM) > 0 && keyPathOverridePEM[0] != "" {
810+
key, err := LoadSinglePEM(keyPathOverridePEM[0])
805811
if err != nil {
806-
return nil, errors.Wrapf(err, "failed to load signing key from %s", signingKey[0])
812+
return nil, errors.Wrapf(err, "failed to load signing key from %s", keyPathOverridePEM[0])
807813
}
808814
return key, nil
809815
}
@@ -837,10 +843,13 @@ func GetIssuerPrivateJWK(signingKey ...string) (jwk.Key, error) {
837843
// this server to sign JWTs it issues. The public key returned will be exposed publicly
838844
// for other servers to verify JWTs signed by this server, typically via a well-known URL
839845
// i.e. "/.well-known/issuer.jwks"
840-
func GetIssuerPublicJWKS(keyPath ...string) (jwk.Set, error) {
846+
//
847+
// The `keyPathOverridePEM` parameter is used to override the default locations by
848+
// providing a PEM file path.
849+
func GetIssuerPublicJWKS(keyPathOverridePEM ...string) (jwk.Set, error) {
841850
existingJWKS := param.Server_IssuerJwks.GetString()
842851
issuerKeysDir := param.IssuerKeysDirectory.GetString()
843-
return loadIssuerPublicJWKS(existingJWKS, issuerKeysDir, keyPath...)
852+
return loadIssuerPublicJWKS(existingJWKS, issuerKeysDir, keyPathOverridePEM...)
844853
}
845854

846855
// Check if there is a session secret exists at param.Server_SessionSecretFile and is not empty if there is one.

0 commit comments

Comments
 (0)