lib/ga4gh/identityutil.go (59 lines of code) (raw):

// Copyright 2019 Google LLC // // 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 ga4gh import ( "crypto/rsa" "fmt" "net/url" "strings" "github.com/go-jose/go-jose/v3" /* copybara-comment */ "github.com/go-jose/go-jose/v3/jwt" /* copybara-comment */ ) // userID returns an user identifier that specifies a subject within an issuer. func userID(subject, issuer string, maxLength int) string { domain := "unknown" if u, err := url.Parse(issuer); err == nil { domain = u.Hostname() } parts := strings.SplitN(subject, "@", 2) if len(parts) < 2 || parts[1] != domain { subject += "|" + domain } // UserID is also used as a description in some cases, and that has a max length // that a long domain name may exceed. if len(subject) > maxLength { subject = subject[0:maxLength] } return subject } // TokenUserID returns an user identifier for a given token. func TokenUserID(token *Identity, maxLength int) string { return userID(token.Subject, token.Issuer, maxLength) } // VerifyTokenWithKey verifies the signature of a token given a public key. func VerifyTokenWithKey(publicKey *rsa.PublicKey, tok string) error { jws, err := jose.ParseSigned(tok) if err != nil { return fmt.Errorf("parsing ID token %v", err) } _, err = jws.Verify(publicKey) return err } // ConvertTokenToIdentityUnsafe unsafely converts a token to an identity. func ConvertTokenToIdentityUnsafe(tok string) (*Identity, error) { parsed, err := jwt.ParseSigned(tok) if err != nil { return nil, fmt.Errorf("parsing JWT: %v", err) } var id Identity if err := parsed.UnsafeClaimsWithoutVerification(&id); err != nil { return nil, fmt.Errorf("extracting base claims without verifying signature: %v", err) } return &id, nil } // HasUserinfoClaims checks if /userinfo endpoint needs to be called to fetch additional claims for // a particular identity. func HasUserinfoClaims(id *Identity) bool { var scopes []string // Hydra is using "scp" claims in access token. if len(id.Scp) > 0 { scopes = id.Scp } else { scopes = strings.Split(id.Scope, " ") } for _, scope := range scopes { if scope == "ga4gh" || scope == "ga4gh_passport_v1" || scope == "identities" { return true } } return false }