")
+ case reflect.Struct, reflect.Map, reflect.Slice:
+ return s.encode, nil
+ }
+
+ // If the map value doesn't have a struct/map/slice, just Encode() it.
+ if err := s.enc.Encode(s.s.Interface()); err != nil {
+ return nil, err
+ }
+ s.buff.Truncate(s.buff.Len() - 1) // Remove Encode added \n
+
+ return nil, nil
+}
+
+func (s *sliceEncode) encode() (stateFn, error) {
+ s.buff.WriteByte(leftParen)
+ for i := 0; i < s.s.Len(); i++ {
+ v := s.s.Index(i)
+ switch s.valueBaseType.Kind() {
+ case reflect.Struct:
+ if v.CanAddr() {
+ v = v.Addr()
+ }
+ if err := marshalStruct(v, s.buff, s.enc); err != nil {
+ return nil, err
+ }
+ case reflect.Map:
+ if err := marshalMap(v, s.buff, s.enc); err != nil {
+ return nil, err
+ }
+ case reflect.Slice:
+ if err := marshalSlice(v, s.buff, s.enc); err != nil {
+ return nil, err
+ }
+ default:
+ panic(fmt.Sprintf("critical bug: mapEncode.encode() called with value base type: %v", s.valueBaseType.Kind()))
+ }
+ s.buff.WriteByte(comma)
+ }
+ s.buff.Truncate(s.buff.Len() - 1) // Remove final comma
+ s.buff.WriteByte(rightParen)
+ return nil, nil
+}
+
+// writeAddFields writes the AdditionalFields struct field out to JSON as field
+// values. i must be a map[string]interface{} or this will panic.
+func writeAddFields(i interface{}, buff *bytes.Buffer, enc *json.Encoder) error {
+ m := i.(map[string]interface{})
+
+ x := 0
+ for k, v := range m {
+ buff.WriteString(fmt.Sprintf("%q:", k))
+ if err := enc.Encode(v); err != nil {
+ return err
+ }
+ buff.Truncate(buff.Len() - 1) // Remove Encode() added \n
+
+ if x+1 != len(m) {
+ buff.WriteByte(comma)
+ }
+ x++
+ }
+ return nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/struct.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/struct.go
new file mode 100644
index 000000000..07751544a
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/struct.go
@@ -0,0 +1,290 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package json
+
+import (
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+func unmarshalStruct(jdec *json.Decoder, i interface{}) error {
+ v := reflect.ValueOf(i)
+ if v.Kind() != reflect.Ptr {
+ return fmt.Errorf("Unmarshal() received type %T, which is not a *struct", i)
+ }
+ v = v.Elem()
+ if v.Kind() != reflect.Struct {
+ return fmt.Errorf("Unmarshal() received type %T, which is not a *struct", i)
+ }
+
+ if hasUnmarshalJSON(v) {
+ // Indicates that this type has a custom Unmarshaler.
+ return jdec.Decode(v.Addr().Interface())
+ }
+
+ f := v.FieldByName(addField)
+ if f.Kind() == reflect.Invalid {
+ return fmt.Errorf("Unmarshal(%T) only supports structs that have the field AdditionalFields or implements json.Unmarshaler", i)
+ }
+
+ if f.Kind() != reflect.Map || !f.Type().AssignableTo(mapStrInterType) {
+ return fmt.Errorf("type %T has field 'AdditionalFields' that is not a map[string]interface{}", i)
+ }
+
+ dec := newDecoder(jdec, v)
+ return dec.run()
+}
+
+type decoder struct {
+ dec *json.Decoder
+ value reflect.Value // This will be a reflect.Struct
+ translator translateFields
+ key string
+}
+
+func newDecoder(dec *json.Decoder, value reflect.Value) *decoder {
+ return &decoder{value: value, dec: dec}
+}
+
+// run runs our decoder state machine.
+func (d *decoder) run() error {
+ var state = d.start
+ var err error
+ for {
+ state, err = state()
+ if err != nil {
+ return err
+ }
+ if state == nil {
+ return nil
+ }
+ }
+}
+
+// start looks for our opening delimeter '{' and then transitions to looping through our fields.
+func (d *decoder) start() (stateFn, error) {
+ var err error
+ d.translator, err = findFields(d.value)
+ if err != nil {
+ return nil, err
+ }
+
+ delim, err := d.dec.Token()
+ if err != nil {
+ return nil, err
+ }
+ if !delimIs(delim, '{') {
+ return nil, fmt.Errorf("Unmarshal expected opening {, received %v", delim)
+ }
+
+ return d.next, nil
+}
+
+// next gets the next struct field name from the raw json or stops the machine if we get our closing }.
+func (d *decoder) next() (stateFn, error) {
+ if !d.dec.More() {
+ // Remove the closing }.
+ if _, err := d.dec.Token(); err != nil {
+ return nil, err
+ }
+ return nil, nil
+ }
+
+ key, err := d.dec.Token()
+ if err != nil {
+ return nil, err
+ }
+
+ d.key = key.(string)
+ return d.storeValue, nil
+}
+
+// storeValue takes the next value and stores it our struct. If the field can't be found
+// in the struct, it pushes the operation to storeAdditional().
+func (d *decoder) storeValue() (stateFn, error) {
+ goName := d.translator.goName(d.key)
+ if goName == "" {
+ goName = d.key
+ }
+
+ // We don't have the field in the struct, so it goes in AdditionalFields.
+ f := d.value.FieldByName(goName)
+ if f.Kind() == reflect.Invalid {
+ return d.storeAdditional, nil
+ }
+
+ // Indicates that this type has a custom Unmarshaler.
+ if hasUnmarshalJSON(f) {
+ err := d.dec.Decode(f.Addr().Interface())
+ if err != nil {
+ return nil, err
+ }
+ return d.next, nil
+ }
+
+ t, isPtr, err := fieldBaseType(d.value, goName)
+ if err != nil {
+ return nil, fmt.Errorf("type(%s) had field(%s) %w", d.value.Type().Name(), goName, err)
+ }
+
+ switch t.Kind() {
+ // We need to recursively call ourselves on any *struct or struct.
+ case reflect.Struct:
+ if isPtr {
+ if f.IsNil() {
+ f.Set(reflect.New(t))
+ }
+ } else {
+ f = f.Addr()
+ }
+ if err := unmarshalStruct(d.dec, f.Interface()); err != nil {
+ return nil, err
+ }
+ return d.next, nil
+ case reflect.Map:
+ v := reflect.MakeMap(f.Type())
+ ptr := newValue(f.Type())
+ ptr.Elem().Set(v)
+ if err := unmarshalMap(d.dec, ptr); err != nil {
+ return nil, err
+ }
+ f.Set(ptr.Elem())
+ return d.next, nil
+ case reflect.Slice:
+ v := reflect.MakeSlice(f.Type(), 0, 0)
+ ptr := newValue(f.Type())
+ ptr.Elem().Set(v)
+ if err := unmarshalSlice(d.dec, ptr); err != nil {
+ return nil, err
+ }
+ f.Set(ptr.Elem())
+ return d.next, nil
+ }
+
+ if !isPtr {
+ f = f.Addr()
+ }
+
+ // For values that are pointers, we need them to be non-nil in order
+ // to decode into them.
+ if f.IsNil() {
+ f.Set(reflect.New(t))
+ }
+
+ if err := d.dec.Decode(f.Interface()); err != nil {
+ return nil, err
+ }
+
+ return d.next, nil
+}
+
+// storeAdditional pushes the key/value into our .AdditionalFields map.
+func (d *decoder) storeAdditional() (stateFn, error) {
+ rw := json.RawMessage{}
+ if err := d.dec.Decode(&rw); err != nil {
+ return nil, err
+ }
+ field := d.value.FieldByName(addField)
+ if field.IsNil() {
+ field.Set(reflect.MakeMap(field.Type()))
+ }
+ field.SetMapIndex(reflect.ValueOf(d.key), reflect.ValueOf(rw))
+ return d.next, nil
+}
+
+func fieldBaseType(v reflect.Value, fieldName string) (t reflect.Type, isPtr bool, err error) {
+ sf, ok := v.Type().FieldByName(fieldName)
+ if !ok {
+ return nil, false, fmt.Errorf("bug: fieldBaseType() lookup of field(%s) on type(%s): do not have field", fieldName, v.Type().Name())
+ }
+ t = sf.Type
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ isPtr = true
+ }
+ if t.Kind() == reflect.Ptr {
+ return nil, isPtr, fmt.Errorf("received pointer to pointer type, not supported")
+ }
+ return t, isPtr, nil
+}
+
+type translateField struct {
+ jsonName string
+ goName string
+}
+
+// translateFields is a list of translateFields with a handy lookup method.
+type translateFields []translateField
+
+// goName loops through a list of fields looking for one contaning the jsonName and
+// returning the goName. If not found, returns the empty string.
+// Note: not a map because at this size slices are faster even in tight loops.
+func (t translateFields) goName(jsonName string) string {
+ for _, entry := range t {
+ if entry.jsonName == jsonName {
+ return entry.goName
+ }
+ }
+ return ""
+}
+
+// jsonName loops through a list of fields looking for one contaning the goName and
+// returning the jsonName. If not found, returns the empty string.
+// Note: not a map because at this size slices are faster even in tight loops.
+func (t translateFields) jsonName(goName string) string {
+ for _, entry := range t {
+ if entry.goName == goName {
+ return entry.jsonName
+ }
+ }
+ return ""
+}
+
+var umarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
+
+// findFields parses a struct and writes the field tags for lookup. It will return an error
+// if any field has a type of *struct or struct that does not implement json.Marshaler.
+func findFields(v reflect.Value) (translateFields, error) {
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ if v.Kind() != reflect.Struct {
+ return nil, fmt.Errorf("findFields received a %s type, expected *struct or struct", v.Type().Name())
+ }
+ tfs := make([]translateField, 0, v.NumField())
+ for i := 0; i < v.NumField(); i++ {
+ tf := translateField{
+ goName: v.Type().Field(i).Name,
+ jsonName: parseTag(v.Type().Field(i).Tag.Get("json")),
+ }
+ switch tf.jsonName {
+ case "", "-":
+ tf.jsonName = tf.goName
+ }
+ tfs = append(tfs, tf)
+
+ f := v.Field(i)
+ if f.Kind() == reflect.Ptr {
+ f = f.Elem()
+ }
+ if f.Kind() == reflect.Struct {
+ if f.Type().Implements(umarshalerType) {
+ return nil, fmt.Errorf("struct type %q which has field %q which "+
+ "doesn't implement json.Unmarshaler", v.Type().Name(), v.Type().Field(i).Name)
+ }
+ }
+ }
+ return tfs, nil
+}
+
+// parseTag just returns the first entry in the tag. tag is the string
+// returned by reflect.StructField.Tag().Get().
+func parseTag(tag string) string {
+ if idx := strings.Index(tag, ","); idx != -1 {
+ return tag[:idx]
+ }
+ return tag
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time/time.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time/time.go
new file mode 100644
index 000000000..a1c99621e
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time/time.go
@@ -0,0 +1,70 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// Package time provides for custom types to translate time from JSON and other formats
+// into time.Time objects.
+package time
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Unix provides a type that can marshal and unmarshal a string representation
+// of the unix epoch into a time.Time object.
+type Unix struct {
+ T time.Time
+}
+
+// MarshalJSON implements encoding/json.MarshalJSON().
+func (u Unix) MarshalJSON() ([]byte, error) {
+ if u.T.IsZero() {
+ return []byte(""), nil
+ }
+ return []byte(fmt.Sprintf("%q", strconv.FormatInt(u.T.Unix(), 10))), nil
+}
+
+// UnmarshalJSON implements encoding/json.UnmarshalJSON().
+func (u *Unix) UnmarshalJSON(b []byte) error {
+ i, err := strconv.Atoi(strings.Trim(string(b), `"`))
+ if err != nil {
+ return fmt.Errorf("unix time(%s) could not be converted from string to int: %w", string(b), err)
+ }
+ u.T = time.Unix(int64(i), 0)
+ return nil
+}
+
+// DurationTime provides a type that can marshal and unmarshal a string representation
+// of a duration from now into a time.Time object.
+// Note: I'm not sure this is the best way to do this. What happens is we get a field
+// called "expires_in" that represents the seconds from now that this expires. We
+// turn that into a time we call .ExpiresOn. But maybe we should be recording
+// when the token was received at .TokenRecieved and .ExpiresIn should remain as a duration.
+// Then we could have a method called ExpiresOn(). Honestly, the whole thing is
+// bad because the server doesn't return a concrete time. I think this is
+// cleaner, but its not great either.
+type DurationTime struct {
+ T time.Time
+}
+
+// MarshalJSON implements encoding/json.MarshalJSON().
+func (d DurationTime) MarshalJSON() ([]byte, error) {
+ if d.T.IsZero() {
+ return []byte(""), nil
+ }
+
+ dt := time.Until(d.T)
+ return []byte(fmt.Sprintf("%d", int64(dt*time.Second))), nil
+}
+
+// UnmarshalJSON implements encoding/json.UnmarshalJSON().
+func (d *DurationTime) UnmarshalJSON(b []byte) error {
+ i, err := strconv.Atoi(strings.Trim(string(b), `"`))
+ if err != nil {
+ return fmt.Errorf("unix time(%s) could not be converted from string to int: %w", string(b), err)
+ }
+ d.T = time.Now().Add(time.Duration(i) * time.Second)
+ return nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go
new file mode 100644
index 000000000..c6baf2094
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local/server.go
@@ -0,0 +1,180 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// Package local contains a local HTTP server used with interactive authentication.
+package local
+
+import (
+ "context"
+ "fmt"
+ "html"
+ "net"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var okPage = []byte(`
+
+
+
+
+ Authentication Complete
+
+
+ Authentication complete. You can return to the application. Feel free to close this browser tab.
+
+
+`)
+
+const failPage = `
+
+
+
+
+ Authentication Failed
+
+
+ Authentication failed. You can return to the application. Feel free to close this browser tab.
+ Error details: error %s error_description: %s
+
+
+`
+
+// Result is the result from the redirect.
+type Result struct {
+ // Code is the code sent by the authority server.
+ Code string
+ // Err is set if there was an error.
+ Err error
+}
+
+// Server is an HTTP server.
+type Server struct {
+ // Addr is the address the server is listening on.
+ Addr string
+ resultCh chan Result
+ s *http.Server
+ reqState string
+}
+
+// New creates a local HTTP server and starts it.
+func New(reqState string, port int) (*Server, error) {
+ var l net.Listener
+ var err error
+ var portStr string
+ if port > 0 {
+ // use port provided by caller
+ l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
+ portStr = strconv.FormatInt(int64(port), 10)
+ } else {
+ // find a free port
+ for i := 0; i < 10; i++ {
+ l, err = net.Listen("tcp", "localhost:0")
+ if err != nil {
+ continue
+ }
+ addr := l.Addr().String()
+ portStr = addr[strings.LastIndex(addr, ":")+1:]
+ break
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ serv := &Server{
+ Addr: fmt.Sprintf("http://localhost:%s", portStr),
+ s: &http.Server{Addr: "localhost:0", ReadHeaderTimeout: time.Second},
+ reqState: reqState,
+ resultCh: make(chan Result, 1),
+ }
+ serv.s.Handler = http.HandlerFunc(serv.handler)
+
+ if err := serv.start(l); err != nil {
+ return nil, err
+ }
+
+ return serv, nil
+}
+
+func (s *Server) start(l net.Listener) error {
+ go func() {
+ err := s.s.Serve(l)
+ if err != nil {
+ select {
+ case s.resultCh <- Result{Err: err}:
+ default:
+ }
+ }
+ }()
+
+ return nil
+}
+
+// Result gets the result of the redirect operation. Once a single result is returned, the server
+// is shutdown. ctx deadline will be honored.
+func (s *Server) Result(ctx context.Context) Result {
+ select {
+ case <-ctx.Done():
+ return Result{Err: ctx.Err()}
+ case r := <-s.resultCh:
+ return r
+ }
+}
+
+// Shutdown shuts down the server.
+func (s *Server) Shutdown() {
+ // Note: You might get clever and think you can do this in handler() as a defer, you can't.
+ _ = s.s.Shutdown(context.Background())
+}
+
+func (s *Server) putResult(r Result) {
+ select {
+ case s.resultCh <- r:
+ default:
+ }
+}
+
+func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query()
+
+ headerErr := q.Get("error")
+ if headerErr != "" {
+ desc := html.EscapeString(q.Get("error_description"))
+ escapedHeaderErr := html.EscapeString(headerErr)
+ // Note: It is a little weird we handle some errors by not going to the failPage. If they all should,
+ // change this to s.error() and make s.error() write the failPage instead of an error code.
+ _, _ = w.Write([]byte(fmt.Sprintf(failPage, escapedHeaderErr, desc)))
+ s.putResult(Result{Err: fmt.Errorf("%s", desc)})
+
+ return
+ }
+
+ respState := q.Get("state")
+ switch respState {
+ case s.reqState:
+ case "":
+ s.error(w, http.StatusInternalServerError, "server didn't send OAuth state")
+ return
+ default:
+ s.error(w, http.StatusInternalServerError, "mismatched OAuth state, req(%s), resp(%s)", s.reqState, respState)
+ return
+ }
+
+ code := q.Get("code")
+ if code == "" {
+ s.error(w, http.StatusInternalServerError, "authorization code missing in query string")
+ return
+ }
+
+ _, _ = w.Write(okPage)
+ s.putResult(Result{Code: code})
+}
+
+func (s *Server) error(w http.ResponseWriter, code int, str string, i ...interface{}) {
+ err := fmt.Errorf(str, i...)
+ http.Error(w, err.Error(), code)
+ s.putResult(Result{Err: err})
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go
new file mode 100644
index 000000000..738a29eb9
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/oauth.go
@@ -0,0 +1,359 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package oauth
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/google/uuid"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/exported"
+ internalTime "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs"
+)
+
+// ResolveEndpointer contains the methods for resolving authority endpoints.
+type ResolveEndpointer interface {
+ ResolveEndpoints(ctx context.Context, authorityInfo authority.Info, userPrincipalName string) (authority.Endpoints, error)
+}
+
+// AccessTokens contains the methods for fetching tokens from different sources.
+type AccessTokens interface {
+ DeviceCodeResult(ctx context.Context, authParameters authority.AuthParams) (accesstokens.DeviceCodeResult, error)
+ FromUsernamePassword(ctx context.Context, authParameters authority.AuthParams) (accesstokens.TokenResponse, error)
+ FromAuthCode(ctx context.Context, req accesstokens.AuthCodeRequest) (accesstokens.TokenResponse, error)
+ FromRefreshToken(ctx context.Context, appType accesstokens.AppType, authParams authority.AuthParams, cc *accesstokens.Credential, refreshToken string) (accesstokens.TokenResponse, error)
+ FromClientSecret(ctx context.Context, authParameters authority.AuthParams, clientSecret string) (accesstokens.TokenResponse, error)
+ FromAssertion(ctx context.Context, authParameters authority.AuthParams, assertion string) (accesstokens.TokenResponse, error)
+ FromUserAssertionClientSecret(ctx context.Context, authParameters authority.AuthParams, userAssertion string, clientSecret string) (accesstokens.TokenResponse, error)
+ FromUserAssertionClientCertificate(ctx context.Context, authParameters authority.AuthParams, userAssertion string, assertion string) (accesstokens.TokenResponse, error)
+ FromDeviceCodeResult(ctx context.Context, authParameters authority.AuthParams, deviceCodeResult accesstokens.DeviceCodeResult) (accesstokens.TokenResponse, error)
+ FromSamlGrant(ctx context.Context, authParameters authority.AuthParams, samlGrant wstrust.SamlTokenInfo) (accesstokens.TokenResponse, error)
+}
+
+// FetchAuthority will be implemented by authority.Authority.
+type FetchAuthority interface {
+ UserRealm(context.Context, authority.AuthParams) (authority.UserRealm, error)
+ AADInstanceDiscovery(context.Context, authority.Info) (authority.InstanceDiscoveryResponse, error)
+}
+
+// FetchWSTrust contains the methods for interacting with WSTrust endpoints.
+type FetchWSTrust interface {
+ Mex(ctx context.Context, federationMetadataURL string) (defs.MexDocument, error)
+ SAMLTokenInfo(ctx context.Context, authParameters authority.AuthParams, cloudAudienceURN string, endpoint defs.Endpoint) (wstrust.SamlTokenInfo, error)
+}
+
+// Client provides tokens for various types of token requests.
+type Client struct {
+ Resolver ResolveEndpointer
+ AccessTokens AccessTokens
+ Authority FetchAuthority
+ WSTrust FetchWSTrust
+}
+
+// New is the constructor for Token.
+func New(httpClient ops.HTTPClient) *Client {
+ r := ops.New(httpClient)
+ return &Client{
+ Resolver: newAuthorityEndpoint(r),
+ AccessTokens: r.AccessTokens(),
+ Authority: r.Authority(),
+ WSTrust: r.WSTrust(),
+ }
+}
+
+// ResolveEndpoints gets the authorization and token endpoints and creates an AuthorityEndpoints instance.
+func (t *Client) ResolveEndpoints(ctx context.Context, authorityInfo authority.Info, userPrincipalName string) (authority.Endpoints, error) {
+ return t.Resolver.ResolveEndpoints(ctx, authorityInfo, userPrincipalName)
+}
+
+// AADInstanceDiscovery attempts to discover a tenant endpoint (used in OIDC auth with an authorization endpoint).
+// This is done by AAD which allows for aliasing of tenants (windows.sts.net is the same as login.windows.com).
+func (t *Client) AADInstanceDiscovery(ctx context.Context, authorityInfo authority.Info) (authority.InstanceDiscoveryResponse, error) {
+ return t.Authority.AADInstanceDiscovery(ctx, authorityInfo)
+}
+
+// AuthCode returns a token based on an authorization code.
+func (t *Client) AuthCode(ctx context.Context, req accesstokens.AuthCodeRequest) (accesstokens.TokenResponse, error) {
+ if err := scopeError(req.AuthParams); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ if err := t.resolveEndpoint(ctx, &req.AuthParams, ""); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ tResp, err := t.AccessTokens.FromAuthCode(ctx, req)
+ if err != nil {
+ return accesstokens.TokenResponse{}, fmt.Errorf("could not retrieve token from auth code: %w", err)
+ }
+ return tResp, nil
+}
+
+// Credential acquires a token from the authority using a client credentials grant.
+func (t *Client) Credential(ctx context.Context, authParams authority.AuthParams, cred *accesstokens.Credential) (accesstokens.TokenResponse, error) {
+ if cred.TokenProvider != nil {
+ now := time.Now()
+ scopes := make([]string, len(authParams.Scopes))
+ copy(scopes, authParams.Scopes)
+ params := exported.TokenProviderParameters{
+ Claims: authParams.Claims,
+ CorrelationID: uuid.New().String(),
+ Scopes: scopes,
+ TenantID: authParams.AuthorityInfo.Tenant,
+ }
+ pr, err := cred.TokenProvider(ctx, params)
+ if err != nil {
+ if len(scopes) == 0 {
+ err = fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which may cause the following error: %w", err)
+ return accesstokens.TokenResponse{}, err
+ }
+ return accesstokens.TokenResponse{}, err
+ }
+ tr := accesstokens.TokenResponse{
+ TokenType: authParams.AuthnScheme.AccessTokenType(),
+ AccessToken: pr.AccessToken,
+ ExpiresOn: now.Add(time.Duration(pr.ExpiresInSeconds) * time.Second),
+ GrantedScopes: accesstokens.Scopes{Slice: authParams.Scopes},
+ }
+ if pr.RefreshInSeconds > 0 {
+ tr.RefreshOn = internalTime.DurationTime{
+ T: now.Add(time.Duration(pr.RefreshInSeconds) * time.Second),
+ }
+ }
+ return tr, nil
+ }
+
+ if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ if cred.Secret != "" {
+ return t.AccessTokens.FromClientSecret(ctx, authParams, cred.Secret)
+ }
+ jwt, err := cred.JWT(ctx, authParams)
+ if err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ return t.AccessTokens.FromAssertion(ctx, authParams, jwt)
+}
+
+// Credential acquires a token from the authority using a client credentials grant.
+func (t *Client) OnBehalfOf(ctx context.Context, authParams authority.AuthParams, cred *accesstokens.Credential) (accesstokens.TokenResponse, error) {
+ if err := scopeError(authParams); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ if cred.Secret != "" {
+ return t.AccessTokens.FromUserAssertionClientSecret(ctx, authParams, authParams.UserAssertion, cred.Secret)
+ }
+ jwt, err := cred.JWT(ctx, authParams)
+ if err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ tr, err := t.AccessTokens.FromUserAssertionClientCertificate(ctx, authParams, authParams.UserAssertion, jwt)
+ if err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ return tr, nil
+}
+
+func (t *Client) Refresh(ctx context.Context, reqType accesstokens.AppType, authParams authority.AuthParams, cc *accesstokens.Credential, refreshToken accesstokens.RefreshToken) (accesstokens.TokenResponse, error) {
+ if err := scopeError(authParams); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ tr, err := t.AccessTokens.FromRefreshToken(ctx, reqType, authParams, cc, refreshToken.Secret)
+ if err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ return tr, nil
+}
+
+// UsernamePassword retrieves a token where a username and password is used. However, if this is
+// a user realm of "Federated", this uses SAML tokens. If "Managed", uses normal username/password.
+func (t *Client) UsernamePassword(ctx context.Context, authParams authority.AuthParams) (accesstokens.TokenResponse, error) {
+ if err := scopeError(authParams); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ if authParams.AuthorityInfo.AuthorityType == authority.ADFS {
+ if err := t.resolveEndpoint(ctx, &authParams, authParams.Username); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ return t.AccessTokens.FromUsernamePassword(ctx, authParams)
+ }
+ if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+
+ userRealm, err := t.Authority.UserRealm(ctx, authParams)
+ if err != nil {
+ return accesstokens.TokenResponse{}, fmt.Errorf("problem getting user realm from authority: %w", err)
+ }
+
+ switch userRealm.AccountType {
+ case authority.Federated:
+ mexDoc, err := t.WSTrust.Mex(ctx, userRealm.FederationMetadataURL)
+ if err != nil {
+ err = fmt.Errorf("problem getting mex doc from federated url(%s): %w", userRealm.FederationMetadataURL, err)
+ return accesstokens.TokenResponse{}, err
+ }
+
+ saml, err := t.WSTrust.SAMLTokenInfo(ctx, authParams, userRealm.CloudAudienceURN, mexDoc.UsernamePasswordEndpoint)
+ if err != nil {
+ err = fmt.Errorf("problem getting SAML token info: %w", err)
+ return accesstokens.TokenResponse{}, err
+ }
+ tr, err := t.AccessTokens.FromSamlGrant(ctx, authParams, saml)
+ if err != nil {
+ return accesstokens.TokenResponse{}, err
+ }
+ return tr, nil
+ case authority.Managed:
+ if len(authParams.Scopes) == 0 {
+ err = fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which may cause the following error: %w", err)
+ return accesstokens.TokenResponse{}, err
+ }
+ return t.AccessTokens.FromUsernamePassword(ctx, authParams)
+ }
+ return accesstokens.TokenResponse{}, errors.New("unknown account type")
+}
+
+// DeviceCode is the result of a call to Token.DeviceCode().
+type DeviceCode struct {
+ // Result is the device code result from the first call in the device code flow. This allows
+ // the caller to retrieve the displayed code that is used to authorize on the second device.
+ Result accesstokens.DeviceCodeResult
+ authParams authority.AuthParams
+
+ accessTokens AccessTokens
+}
+
+// Token returns a token AFTER the user uses the user code on the second device. This will block
+// until either: (1) the code is input by the user and the service releases a token, (2) the token
+// expires, (3) the Context passed to .DeviceCode() is cancelled or expires, (4) some other service
+// error occurs.
+func (d DeviceCode) Token(ctx context.Context) (accesstokens.TokenResponse, error) {
+ if d.accessTokens == nil {
+ return accesstokens.TokenResponse{}, fmt.Errorf("DeviceCode was either created outside its package or the creating method had an error. DeviceCode is not valid")
+ }
+
+ var cancel context.CancelFunc
+ if deadline, ok := ctx.Deadline(); !ok || d.Result.ExpiresOn.Before(deadline) {
+ ctx, cancel = context.WithDeadline(ctx, d.Result.ExpiresOn)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
+ }
+ defer cancel()
+
+ var interval = 50 * time.Millisecond
+ timer := time.NewTimer(interval)
+ defer timer.Stop()
+
+ for {
+ timer.Reset(interval)
+ select {
+ case <-ctx.Done():
+ return accesstokens.TokenResponse{}, ctx.Err()
+ case <-timer.C:
+ interval += interval * 2
+ if interval > 5*time.Second {
+ interval = 5 * time.Second
+ }
+ }
+
+ token, err := d.accessTokens.FromDeviceCodeResult(ctx, d.authParams, d.Result)
+ if err != nil && isWaitDeviceCodeErr(err) {
+ continue
+ }
+ return token, err // This handles if it was a non-wait error or success
+ }
+}
+
+type deviceCodeError struct {
+ Error string `json:"error"`
+}
+
+func isWaitDeviceCodeErr(err error) bool {
+ var c errors.CallErr
+ if !errors.As(err, &c) {
+ return false
+ }
+ if c.Resp.StatusCode != 400 {
+ return false
+ }
+ var dCErr deviceCodeError
+ defer c.Resp.Body.Close()
+ body, err := io.ReadAll(c.Resp.Body)
+ if err != nil {
+ return false
+ }
+ err = json.Unmarshal(body, &dCErr)
+ if err != nil {
+ return false
+ }
+ if dCErr.Error == "authorization_pending" || dCErr.Error == "slow_down" {
+ return true
+ }
+ return false
+}
+
+// DeviceCode returns a DeviceCode object that can be used to get the code that must be entered on the second
+// device and optionally the token once the code has been entered on the second device.
+func (t *Client) DeviceCode(ctx context.Context, authParams authority.AuthParams) (DeviceCode, error) {
+ if err := scopeError(authParams); err != nil {
+ return DeviceCode{}, err
+ }
+
+ if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
+ return DeviceCode{}, err
+ }
+
+ dcr, err := t.AccessTokens.DeviceCodeResult(ctx, authParams)
+ if err != nil {
+ return DeviceCode{}, err
+ }
+
+ return DeviceCode{Result: dcr, authParams: authParams, accessTokens: t.AccessTokens}, nil
+}
+
+func (t *Client) resolveEndpoint(ctx context.Context, authParams *authority.AuthParams, userPrincipalName string) error {
+ endpoints, err := t.Resolver.ResolveEndpoints(ctx, authParams.AuthorityInfo, userPrincipalName)
+ if err != nil {
+ return fmt.Errorf("unable to resolve an endpoint: %w", err)
+ }
+ authParams.Endpoints = endpoints
+ return nil
+}
+
+// scopeError takes an authority.AuthParams and returns an error
+// if len(AuthParams.Scope) == 0.
+func scopeError(a authority.AuthParams) error {
+ // TODO(someone): we could look deeper at the message to determine if
+ // it's a scope error, but this is a good start.
+ /*
+ {error":"invalid_scope","error_description":"AADSTS1002012: The provided value for scope
+ openid offline_access profile is not valid. Client credential flows must have a scope value
+ with /.default suffixed to the resource identifier (application ID URI)...}
+ */
+ if len(a.Scopes) == 0 {
+ return fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which is invalid")
+ }
+ return nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
new file mode 100644
index 000000000..481f9e434
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
@@ -0,0 +1,485 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/*
+Package accesstokens exposes a REST client for querying backend systems to get various types of
+access tokens (oauth) for use in authentication.
+
+These calls are of type "application/x-www-form-urlencoded". This means we use url.Values to
+represent arguments and then encode them into the POST body message. We receive JSON in
+return for the requests. The request definition is defined in https://tools.ietf.org/html/rfc7521#section-4.2 .
+*/
+package accesstokens
+
+import (
+ "context"
+ "crypto"
+
+ /* #nosec */
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/exported"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust"
+ "github.com/golang-jwt/jwt/v5"
+ "github.com/google/uuid"
+)
+
+const (
+ grantType = "grant_type"
+ deviceCode = "device_code"
+ clientID = "client_id"
+ clientInfo = "client_info"
+ clientInfoVal = "1"
+ username = "username"
+ password = "password"
+)
+
+//go:generate stringer -type=AppType
+
+// AppType is whether the authorization code flow is for a public or confidential client.
+type AppType int8
+
+const (
+ // ATUnknown is the zero value when the type hasn't been set.
+ ATUnknown AppType = iota
+ // ATPublic indicates this if for the Public.Client.
+ ATPublic
+ // ATConfidential indicates this if for the Confidential.Client.
+ ATConfidential
+)
+
+type urlFormCaller interface {
+ URLFormCall(ctx context.Context, endpoint string, qv url.Values, resp interface{}) error
+}
+
+// DeviceCodeResponse represents the HTTP response received from the device code endpoint
+type DeviceCodeResponse struct {
+ authority.OAuthResponseBase
+
+ UserCode string `json:"user_code"`
+ DeviceCode string `json:"device_code"`
+ VerificationURL string `json:"verification_uri"`
+ ExpiresIn int `json:"expires_in"`
+ Interval int `json:"interval"`
+ Message string `json:"message"`
+
+ AdditionalFields map[string]interface{}
+}
+
+// Convert converts the DeviceCodeResponse to a DeviceCodeResult
+func (dcr DeviceCodeResponse) Convert(clientID string, scopes []string) DeviceCodeResult {
+ expiresOn := time.Now().UTC().Add(time.Duration(dcr.ExpiresIn) * time.Second)
+ return NewDeviceCodeResult(dcr.UserCode, dcr.DeviceCode, dcr.VerificationURL, expiresOn, dcr.Interval, dcr.Message, clientID, scopes)
+}
+
+// Credential represents the credential used in confidential client flows. This can be either
+// a Secret or Cert/Key.
+type Credential struct {
+ // Secret contains the credential secret if we are doing auth by secret.
+ Secret string
+
+ // Cert is the public certificate, if we're authenticating by certificate.
+ Cert *x509.Certificate
+ // Key is the private key for signing, if we're authenticating by certificate.
+ Key crypto.PrivateKey
+ // X5c is the JWT assertion's x5c header value, required for SN/I authentication.
+ X5c []string
+
+ // AssertionCallback is a function provided by the application, if we're authenticating by assertion.
+ AssertionCallback func(context.Context, exported.AssertionRequestOptions) (string, error)
+
+ // TokenProvider is a function provided by the application that implements custom authentication
+ // logic for a confidential client
+ TokenProvider func(context.Context, exported.TokenProviderParameters) (exported.TokenProviderResult, error)
+}
+
+// JWT gets the jwt assertion when the credential is not using a secret.
+func (c *Credential) JWT(ctx context.Context, authParams authority.AuthParams) (string, error) {
+ if c.AssertionCallback != nil {
+ options := exported.AssertionRequestOptions{
+ ClientID: authParams.ClientID,
+ TokenEndpoint: authParams.Endpoints.TokenEndpoint,
+ }
+ return c.AssertionCallback(ctx, options)
+ }
+ claims := jwt.MapClaims{
+ "aud": authParams.Endpoints.TokenEndpoint,
+ "exp": json.Number(strconv.FormatInt(time.Now().Add(10*time.Minute).Unix(), 10)),
+ "iss": authParams.ClientID,
+ "jti": uuid.New().String(),
+ "nbf": json.Number(strconv.FormatInt(time.Now().Unix(), 10)),
+ "sub": authParams.ClientID,
+ }
+
+ isADFSorDSTS := authParams.AuthorityInfo.AuthorityType == authority.ADFS ||
+ authParams.AuthorityInfo.AuthorityType == authority.DSTS
+
+ var signingMethod jwt.SigningMethod = jwt.SigningMethodPS256
+ thumbprintKey := "x5t#S256"
+
+ if isADFSorDSTS {
+ signingMethod = jwt.SigningMethodRS256
+ thumbprintKey = "x5t"
+ }
+
+ token := jwt.NewWithClaims(signingMethod, claims)
+ token.Header = map[string]interface{}{
+ "alg": signingMethod.Alg(),
+ "typ": "JWT",
+ thumbprintKey: base64.StdEncoding.EncodeToString(thumbprint(c.Cert, signingMethod.Alg())),
+ }
+
+ if authParams.SendX5C {
+ token.Header["x5c"] = c.X5c
+ }
+
+ assertion, err := token.SignedString(c.Key)
+ if err != nil {
+ return "", fmt.Errorf("unable to sign JWT token: %w", err)
+ }
+
+ return assertion, nil
+}
+
+// thumbprint runs the asn1.Der bytes through sha1 for use in the x5t parameter of JWT.
+// https://tools.ietf.org/html/rfc7517#section-4.8
+func thumbprint(cert *x509.Certificate, alg string) []byte {
+ switch alg {
+ case jwt.SigningMethodRS256.Name: // identity providers like ADFS don't support SHA256 assertions, so need to support this
+ hash := sha1.Sum(cert.Raw) /* #nosec */
+ return hash[:]
+ default:
+ hash := sha256.Sum256(cert.Raw)
+ return hash[:]
+ }
+}
+
+// Client represents the REST calls to get tokens from token generator backends.
+type Client struct {
+ // Comm provides the HTTP transport client.
+ Comm urlFormCaller
+
+ testing bool
+}
+
+// FromUsernamePassword uses a username and password to get an access token.
+func (c Client) FromUsernamePassword(ctx context.Context, authParameters authority.AuthParams) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.Password)
+ qv.Set(username, authParameters.Username)
+ qv.Set(password, authParameters.Password)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ addScopeQueryParam(qv, authParameters)
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+// AuthCodeRequest stores the values required to request a token from the authority using an authorization code
+type AuthCodeRequest struct {
+ AuthParams authority.AuthParams
+ Code string
+ CodeChallenge string
+ Credential *Credential
+ AppType AppType
+}
+
+// NewCodeChallengeRequest returns an AuthCodeRequest that uses a code challenge..
+func NewCodeChallengeRequest(params authority.AuthParams, appType AppType, cc *Credential, code, challenge string) (AuthCodeRequest, error) {
+ if appType == ATUnknown {
+ return AuthCodeRequest{}, fmt.Errorf("bug: NewCodeChallengeRequest() called with AppType == ATUnknown")
+ }
+ return AuthCodeRequest{
+ AuthParams: params,
+ AppType: appType,
+ Code: code,
+ CodeChallenge: challenge,
+ Credential: cc,
+ }, nil
+}
+
+// FromAuthCode uses an authorization code to retrieve an access token.
+func (c Client) FromAuthCode(ctx context.Context, req AuthCodeRequest) (TokenResponse, error) {
+ var qv url.Values
+
+ switch req.AppType {
+ case ATUnknown:
+ return TokenResponse{}, fmt.Errorf("bug: Token.AuthCode() received request with AppType == ATUnknown")
+ case ATConfidential:
+ var err error
+ if req.Credential == nil {
+ return TokenResponse{}, fmt.Errorf("AuthCodeRequest had nil Credential for Confidential app")
+ }
+ qv, err = prepURLVals(ctx, req.Credential, req.AuthParams)
+ if err != nil {
+ return TokenResponse{}, err
+ }
+ case ATPublic:
+ qv = url.Values{}
+ default:
+ return TokenResponse{}, fmt.Errorf("bug: Token.AuthCode() received request with AppType == %v, which we do not recongnize", req.AppType)
+ }
+
+ qv.Set(grantType, grant.AuthCode)
+ qv.Set("code", req.Code)
+ qv.Set("code_verifier", req.CodeChallenge)
+ qv.Set("redirect_uri", req.AuthParams.Redirecturi)
+ qv.Set(clientID, req.AuthParams.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ addScopeQueryParam(qv, req.AuthParams)
+ if err := addClaims(qv, req.AuthParams); err != nil {
+ return TokenResponse{}, err
+ }
+
+ return c.doTokenResp(ctx, req.AuthParams, qv)
+}
+
+// FromRefreshToken uses a refresh token (for refreshing credentials) to get a new access token.
+func (c Client) FromRefreshToken(ctx context.Context, appType AppType, authParams authority.AuthParams, cc *Credential, refreshToken string) (TokenResponse, error) {
+ qv := url.Values{}
+ if appType == ATConfidential {
+ var err error
+ qv, err = prepURLVals(ctx, cc, authParams)
+ if err != nil {
+ return TokenResponse{}, err
+ }
+ }
+ if err := addClaims(qv, authParams); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.RefreshToken)
+ qv.Set(clientID, authParams.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ qv.Set("refresh_token", refreshToken)
+ addScopeQueryParam(qv, authParams)
+
+ return c.doTokenResp(ctx, authParams, qv)
+}
+
+// FromClientSecret uses a client's secret (aka password) to get a new token.
+func (c Client) FromClientSecret(ctx context.Context, authParameters authority.AuthParams, clientSecret string) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.ClientCredential)
+ qv.Set("client_secret", clientSecret)
+ qv.Set(clientID, authParameters.ClientID)
+ addScopeQueryParam(qv, authParameters)
+
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) FromAssertion(ctx context.Context, authParameters authority.AuthParams, assertion string) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.ClientCredential)
+ qv.Set("client_assertion_type", grant.ClientAssertion)
+ qv.Set("client_assertion", assertion)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ addScopeQueryParam(qv, authParameters)
+
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) FromUserAssertionClientSecret(ctx context.Context, authParameters authority.AuthParams, userAssertion string, clientSecret string) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.JWT)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set("client_secret", clientSecret)
+ qv.Set("assertion", userAssertion)
+ qv.Set(clientInfo, clientInfoVal)
+ qv.Set("requested_token_use", "on_behalf_of")
+ addScopeQueryParam(qv, authParameters)
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) FromUserAssertionClientCertificate(ctx context.Context, authParameters authority.AuthParams, userAssertion string, assertion string) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.JWT)
+ qv.Set("client_assertion_type", grant.ClientAssertion)
+ qv.Set("client_assertion", assertion)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set("assertion", userAssertion)
+ qv.Set(clientInfo, clientInfoVal)
+ qv.Set("requested_token_use", "on_behalf_of")
+ addScopeQueryParam(qv, authParameters)
+
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) DeviceCodeResult(ctx context.Context, authParameters authority.AuthParams) (DeviceCodeResult, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return DeviceCodeResult{}, err
+ }
+ qv.Set(clientID, authParameters.ClientID)
+ addScopeQueryParam(qv, authParameters)
+
+ endpoint := strings.Replace(authParameters.Endpoints.TokenEndpoint, "token", "devicecode", -1)
+
+ resp := DeviceCodeResponse{}
+ err := c.Comm.URLFormCall(ctx, endpoint, qv, &resp)
+ if err != nil {
+ return DeviceCodeResult{}, err
+ }
+
+ return resp.Convert(authParameters.ClientID, authParameters.Scopes), nil
+}
+
+func (c Client) FromDeviceCodeResult(ctx context.Context, authParameters authority.AuthParams, deviceCodeResult DeviceCodeResult) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(grantType, grant.DeviceCode)
+ qv.Set(deviceCode, deviceCodeResult.DeviceCode)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ addScopeQueryParam(qv, authParameters)
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) FromSamlGrant(ctx context.Context, authParameters authority.AuthParams, samlGrant wstrust.SamlTokenInfo) (TokenResponse, error) {
+ qv := url.Values{}
+ if err := addClaims(qv, authParameters); err != nil {
+ return TokenResponse{}, err
+ }
+ qv.Set(username, authParameters.Username)
+ qv.Set(password, authParameters.Password)
+ qv.Set(clientID, authParameters.ClientID)
+ qv.Set(clientInfo, clientInfoVal)
+ qv.Set("assertion", base64.StdEncoding.WithPadding(base64.StdPadding).EncodeToString([]byte(samlGrant.Assertion)))
+ addScopeQueryParam(qv, authParameters)
+
+ switch samlGrant.AssertionType {
+ case grant.SAMLV1:
+ qv.Set(grantType, grant.SAMLV1)
+ case grant.SAMLV2:
+ qv.Set(grantType, grant.SAMLV2)
+ default:
+ return TokenResponse{}, fmt.Errorf("GetAccessTokenFromSamlGrant returned unknown SAML assertion type: %q", samlGrant.AssertionType)
+ }
+
+ return c.doTokenResp(ctx, authParameters, qv)
+}
+
+func (c Client) doTokenResp(ctx context.Context, authParams authority.AuthParams, qv url.Values) (TokenResponse, error) {
+ resp := TokenResponse{}
+ if authParams.AuthnScheme != nil {
+ trParams := authParams.AuthnScheme.TokenRequestParams()
+ for k, v := range trParams {
+ qv.Set(k, v)
+ }
+ }
+ err := c.Comm.URLFormCall(ctx, authParams.Endpoints.TokenEndpoint, qv, &resp)
+ if err != nil {
+ return resp, err
+ }
+ resp.ComputeScope(authParams)
+ if c.testing {
+ return resp, nil
+ }
+ return resp, resp.Validate()
+}
+
+// prepURLVals returns an url.Values that sets various key/values if we are doing secrets
+// or JWT assertions.
+func prepURLVals(ctx context.Context, cc *Credential, authParams authority.AuthParams) (url.Values, error) {
+ params := url.Values{}
+ if cc.Secret != "" {
+ params.Set("client_secret", cc.Secret)
+ return params, nil
+ }
+
+ jwt, err := cc.JWT(ctx, authParams)
+ if err != nil {
+ return nil, err
+ }
+ params.Set("client_assertion", jwt)
+ params.Set("client_assertion_type", grant.ClientAssertion)
+ return params, nil
+}
+
+// openid required to get an id token
+// offline_access required to get a refresh token
+// profile required to get the client_info field back
+var detectDefaultScopes = map[string]bool{
+ "openid": true,
+ "offline_access": true,
+ "profile": true,
+}
+
+var defaultScopes = []string{"openid", "offline_access", "profile"}
+
+func AppendDefaultScopes(authParameters authority.AuthParams) []string {
+ scopes := make([]string, 0, len(authParameters.Scopes)+len(defaultScopes))
+ for _, scope := range authParameters.Scopes {
+ s := strings.TrimSpace(scope)
+ if s == "" {
+ continue
+ }
+ if detectDefaultScopes[scope] {
+ continue
+ }
+ scopes = append(scopes, scope)
+ }
+ scopes = append(scopes, defaultScopes...)
+ return scopes
+}
+
+// addClaims adds client capabilities and claims from AuthParams to the given url.Values
+func addClaims(v url.Values, ap authority.AuthParams) error {
+ claims, err := ap.MergeCapabilitiesAndClaims()
+ if err == nil && claims != "" {
+ v.Set("claims", claims)
+ }
+ return err
+}
+
+func addScopeQueryParam(queryParams url.Values, authParameters authority.AuthParams) {
+ scopes := AppendDefaultScopes(authParameters)
+ queryParams.Set("scope", strings.Join(scopes, " "))
+}
+
+// addExtraBodyParameters evaluates and adds extra body parameters to the request
+func addExtraBodyParameters(ctx context.Context, v url.Values, ap authority.AuthParams) {
+ for key, value := range ap.ExtraBodyParameters {
+ if value != "" {
+ v.Set(key, value)
+ }
+ }
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/apptype_string.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/apptype_string.go
new file mode 100644
index 000000000..3bec4a67c
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/apptype_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type=AppType"; DO NOT EDIT.
+
+package accesstokens
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[ATUnknown-0]
+ _ = x[ATPublic-1]
+ _ = x[ATConfidential-2]
+}
+
+const _AppType_name = "ATUnknownATPublicATConfidential"
+
+var _AppType_index = [...]uint8{0, 9, 17, 31}
+
+func (i AppType) String() string {
+ if i < 0 || i >= AppType(len(_AppType_index)-1) {
+ return "AppType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _AppType_name[_AppType_index[i]:_AppType_index[i+1]]
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/tokens.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/tokens.go
new file mode 100644
index 000000000..32dde7b76
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/tokens.go
@@ -0,0 +1,401 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package accesstokens
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ internalTime "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared"
+)
+
+// IDToken consists of all the information used to validate a user.
+// https://docs.microsoft.com/azure/active-directory/develop/id-tokens .
+type IDToken struct {
+ PreferredUsername string `json:"preferred_username,omitempty"`
+ GivenName string `json:"given_name,omitempty"`
+ FamilyName string `json:"family_name,omitempty"`
+ MiddleName string `json:"middle_name,omitempty"`
+ Name string `json:"name,omitempty"`
+ Oid string `json:"oid,omitempty"`
+ TenantID string `json:"tid,omitempty"`
+ Subject string `json:"sub,omitempty"`
+ UPN string `json:"upn,omitempty"`
+ Email string `json:"email,omitempty"`
+ AlternativeID string `json:"alternative_id,omitempty"`
+ Issuer string `json:"iss,omitempty"`
+ Audience string `json:"aud,omitempty"`
+ ExpirationTime int64 `json:"exp,omitempty"`
+ IssuedAt int64 `json:"iat,omitempty"`
+ NotBefore int64 `json:"nbf,omitempty"`
+ RawToken string
+
+ AdditionalFields map[string]interface{}
+}
+
+var null = []byte("null")
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (i *IDToken) UnmarshalJSON(b []byte) error {
+ if bytes.Equal(null, b) {
+ return nil
+ }
+
+ // Because we have a custom unmarshaler, you
+ // cannot directly call json.Unmarshal here. If you do, it will call this function
+ // recursively until reach our recursion limit. We have to create a new type
+ // that doesn't have this method in order to use json.Unmarshal.
+ type idToken2 IDToken
+
+ jwt := strings.Trim(string(b), `"`)
+ jwtArr := strings.Split(jwt, ".")
+ if len(jwtArr) < 2 {
+ return errors.New("IDToken returned from server is invalid")
+ }
+
+ jwtPart := jwtArr[1]
+ jwtDecoded, err := decodeJWT(jwtPart)
+ if err != nil {
+ return fmt.Errorf("unable to unmarshal IDToken, problem decoding JWT: %w", err)
+ }
+
+ token := idToken2{}
+ err = json.Unmarshal(jwtDecoded, &token)
+ if err != nil {
+ return fmt.Errorf("unable to unmarshal IDToken: %w", err)
+ }
+ token.RawToken = jwt
+
+ *i = IDToken(token)
+ return nil
+}
+
+// IsZero indicates if the IDToken is the zero value.
+func (i IDToken) IsZero() bool {
+ v := reflect.ValueOf(i)
+ for i := 0; i < v.NumField(); i++ {
+ field := v.Field(i)
+ if !field.IsZero() {
+ switch field.Kind() {
+ case reflect.Map, reflect.Slice:
+ if field.Len() == 0 {
+ continue
+ }
+ }
+ return false
+ }
+ }
+ return true
+}
+
+// LocalAccountID extracts an account's local account ID from an ID token.
+func (i IDToken) LocalAccountID() string {
+ if i.Oid != "" {
+ return i.Oid
+ }
+ return i.Subject
+}
+
+// jwtDecoder is provided to allow tests to provide their own.
+var jwtDecoder = decodeJWT
+
+// ClientInfo is used to create a Home Account ID for an account.
+type ClientInfo struct {
+ UID string `json:"uid"`
+ UTID string `json:"utid"`
+
+ AdditionalFields map[string]interface{}
+}
+
+// UnmarshalJSON implements json.Unmarshaler.s
+func (c *ClientInfo) UnmarshalJSON(b []byte) error {
+ s := strings.Trim(string(b), `"`)
+ // Client info may be empty in some flows, e.g. certificate exchange.
+ if len(s) == 0 {
+ return nil
+ }
+
+ // Because we have a custom unmarshaler, you
+ // cannot directly call json.Unmarshal here. If you do, it will call this function
+ // recursively until reach our recursion limit. We have to create a new type
+ // that doesn't have this method in order to use json.Unmarshal.
+ type clientInfo2 ClientInfo
+
+ raw, err := jwtDecoder(s)
+ if err != nil {
+ return fmt.Errorf("TokenResponse client_info field had JWT decode error: %w", err)
+ }
+
+ var c2 clientInfo2
+
+ err = json.Unmarshal(raw, &c2)
+ if err != nil {
+ return fmt.Errorf("was unable to unmarshal decoded JWT in TokenRespone to ClientInfo: %w", err)
+ }
+
+ *c = ClientInfo(c2)
+ return nil
+}
+
+// Scopes represents scopes in a TokenResponse.
+type Scopes struct {
+ Slice []string
+}
+
+// UnmarshalJSON implements json.Unmarshal.
+func (s *Scopes) UnmarshalJSON(b []byte) error {
+ str := strings.Trim(string(b), `"`)
+ if len(str) == 0 {
+ return nil
+ }
+ sl := strings.Split(str, " ")
+ s.Slice = sl
+ return nil
+}
+
+// TokenResponse is the information that is returned from a token endpoint during a token acquisition flow.
+type TokenResponse struct {
+ authority.OAuthResponseBase
+
+ AccessToken string `json:"access_token"`
+ RefreshToken string `json:"refresh_token"`
+ TokenType string `json:"token_type"`
+
+ FamilyID string `json:"foci"`
+ IDToken IDToken `json:"id_token"`
+ ClientInfo ClientInfo `json:"client_info"`
+ RefreshOn internalTime.DurationTime `json:"refresh_in,omitempty"`
+ ExpiresOn time.Time `json:"-"`
+ ExtExpiresOn internalTime.DurationTime `json:"ext_expires_in"`
+ GrantedScopes Scopes `json:"scope"`
+ DeclinedScopes []string // This is derived
+
+ AdditionalFields map[string]interface{}
+ scopesComputed bool
+}
+
+func (tr *TokenResponse) UnmarshalJSON(data []byte) error {
+ type Alias TokenResponse
+ aux := &struct {
+ ExpiresIn internalTime.DurationTime `json:"expires_in,omitempty"`
+ ExpiresOn any `json:"expires_on,omitempty"`
+ *Alias
+ }{
+ Alias: (*Alias)(tr),
+ }
+
+ // Unmarshal the JSON data into the aux struct
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
+ }
+
+ // Function to parse different date formats
+ // This is a workaround for the issue described here:
+ // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4963
+ parseExpiresOn := func(expiresOn string) (time.Time, error) {
+ var formats = []string{
+ "01/02/2006 15:04:05", // MM/dd/yyyy HH:mm:ss
+ "2006-01-02 15:04:05", // yyyy-MM-dd HH:mm:ss
+ time.RFC3339Nano, // ISO 8601 (with nanosecond precision)
+ }
+
+ for _, format := range formats {
+ if t, err := time.Parse(format, expiresOn); err == nil {
+ return t, nil
+ }
+ }
+ return time.Time{}, fmt.Errorf("invalid ExpiresOn format: %s", expiresOn)
+ }
+
+ if expiresOnStr, ok := aux.ExpiresOn.(string); ok {
+ if ts, err := strconv.ParseInt(expiresOnStr, 10, 64); err == nil {
+ tr.ExpiresOn = time.Unix(ts, 0)
+ return nil
+ }
+ if expiresOnStr != "" {
+ if t, err := parseExpiresOn(expiresOnStr); err != nil {
+ return err
+ } else {
+ tr.ExpiresOn = t
+ return nil
+ }
+ }
+ }
+
+ // Check if ExpiresOn is a number (Unix timestamp or ISO 8601)
+ if expiresOnNum, ok := aux.ExpiresOn.(float64); ok {
+ tr.ExpiresOn = time.Unix(int64(expiresOnNum), 0)
+ return nil
+ }
+
+ if !aux.ExpiresIn.T.IsZero() {
+ tr.ExpiresOn = aux.ExpiresIn.T
+ return nil
+ }
+ return errors.New("expires_in and expires_on are both missing or invalid")
+}
+
+// ComputeScope computes the final scopes based on what was granted by the server and
+// what our AuthParams were from the authority server. Per OAuth spec, if no scopes are returned, the response should be treated as if all scopes were granted
+// This behavior can be observed in client assertion flows, but can happen at any time, this check ensures we treat
+// those special responses properly Link to spec: https://tools.ietf.org/html/rfc6749#section-3.3
+func (tr *TokenResponse) ComputeScope(authParams authority.AuthParams) {
+ if len(tr.GrantedScopes.Slice) == 0 {
+ tr.GrantedScopes = Scopes{Slice: authParams.Scopes}
+ } else {
+ tr.DeclinedScopes = findDeclinedScopes(authParams.Scopes, tr.GrantedScopes.Slice)
+ }
+ tr.scopesComputed = true
+}
+
+// HomeAccountID uniquely identifies the authenticated account, if any. It's "" when the token is an app token.
+func (tr *TokenResponse) HomeAccountID() string {
+ id := tr.IDToken.Subject
+ if uid := tr.ClientInfo.UID; uid != "" {
+ utid := tr.ClientInfo.UTID
+ if utid == "" {
+ utid = uid
+ }
+ id = fmt.Sprintf("%s.%s", uid, utid)
+ }
+ return id
+}
+
+// Validate validates the TokenResponse has basic valid values. It must be called
+// after ComputeScopes() is called.
+func (tr *TokenResponse) Validate() error {
+ if tr.Error != "" {
+ return fmt.Errorf("%s: %s", tr.Error, tr.ErrorDescription)
+ }
+
+ if tr.AccessToken == "" {
+ return errors.New("response is missing access_token")
+ }
+
+ if !tr.scopesComputed {
+ return fmt.Errorf("TokenResponse hasn't had ScopesComputed() called")
+ }
+ return nil
+}
+
+func (tr *TokenResponse) CacheKey(authParams authority.AuthParams) string {
+ if authParams.AuthorizationType == authority.ATOnBehalfOf {
+ return authParams.AssertionHash()
+ }
+ if authParams.AuthorizationType == authority.ATClientCredentials {
+ return authParams.AppKey()
+ }
+ if authParams.IsConfidentialClient || authParams.AuthorizationType == authority.ATRefreshToken {
+ return tr.HomeAccountID()
+ }
+ return ""
+}
+
+func findDeclinedScopes(requestedScopes []string, grantedScopes []string) []string {
+ declined := []string{}
+ grantedMap := map[string]bool{}
+ for _, s := range grantedScopes {
+ grantedMap[strings.ToLower(s)] = true
+ }
+ // Comparing the requested scopes with the granted scopes to see if there are any scopes that have been declined.
+ for _, r := range requestedScopes {
+ if !grantedMap[strings.ToLower(r)] {
+ declined = append(declined, r)
+ }
+ }
+ return declined
+}
+
+// decodeJWT decodes a JWT and converts it to a byte array representing a JSON object
+// JWT has headers and payload base64url encoded without padding
+// https://tools.ietf.org/html/rfc7519#section-3 and
+// https://tools.ietf.org/html/rfc7515#section-2
+func decodeJWT(data string) ([]byte, error) {
+ // https://tools.ietf.org/html/rfc7515#appendix-C
+ return base64.RawURLEncoding.DecodeString(data)
+}
+
+// RefreshToken is the JSON representation of a MSAL refresh token for encoding to storage.
+type RefreshToken struct {
+ HomeAccountID string `json:"home_account_id,omitempty"`
+ Environment string `json:"environment,omitempty"`
+ CredentialType string `json:"credential_type,omitempty"`
+ ClientID string `json:"client_id,omitempty"`
+ FamilyID string `json:"family_id,omitempty"`
+ Secret string `json:"secret,omitempty"`
+ Realm string `json:"realm,omitempty"`
+ Target string `json:"target,omitempty"`
+ UserAssertionHash string `json:"user_assertion_hash,omitempty"`
+
+ AdditionalFields map[string]interface{}
+}
+
+// NewRefreshToken is the constructor for RefreshToken.
+func NewRefreshToken(homeID, env, clientID, refreshToken, familyID string) RefreshToken {
+ return RefreshToken{
+ HomeAccountID: homeID,
+ Environment: env,
+ CredentialType: "RefreshToken",
+ ClientID: clientID,
+ FamilyID: familyID,
+ Secret: refreshToken,
+ }
+}
+
+// Key outputs the key that can be used to uniquely look up this entry in a map.
+func (rt RefreshToken) Key() string {
+ var fourth = rt.FamilyID
+ if fourth == "" {
+ fourth = rt.ClientID
+ }
+
+ key := strings.Join(
+ []string{rt.HomeAccountID, rt.Environment, rt.CredentialType, fourth},
+ shared.CacheKeySeparator,
+ )
+ return strings.ToLower(key)
+}
+
+func (rt RefreshToken) GetSecret() string {
+ return rt.Secret
+}
+
+// DeviceCodeResult stores the response from the STS device code endpoint.
+type DeviceCodeResult struct {
+ // UserCode is the code the user needs to provide when authentication at the verification URI.
+ UserCode string
+ // DeviceCode is the code used in the access token request.
+ DeviceCode string
+ // VerificationURL is the the URL where user can authenticate.
+ VerificationURL string
+ // ExpiresOn is the expiration time of device code in seconds.
+ ExpiresOn time.Time
+ // Interval is the interval at which the STS should be polled at.
+ Interval int
+ // Message is the message which should be displayed to the user.
+ Message string
+ // ClientID is the UUID issued by the authorization server for your application.
+ ClientID string
+ // Scopes is the OpenID scopes used to request access a protected API.
+ Scopes []string
+}
+
+// NewDeviceCodeResult creates a DeviceCodeResult instance.
+func NewDeviceCodeResult(userCode, deviceCode, verificationURL string, expiresOn time.Time, interval int, message, clientID string, scopes []string) DeviceCodeResult {
+ return DeviceCodeResult{userCode, deviceCode, verificationURL, expiresOn, interval, message, clientID, scopes}
+}
+
+func (dcr DeviceCodeResult) String() string {
+ return fmt.Sprintf("UserCode: (%v)\nDeviceCode: (%v)\nURL: (%v)\nMessage: (%v)\n", dcr.UserCode, dcr.DeviceCode, dcr.VerificationURL, dcr.Message)
+
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
new file mode 100644
index 000000000..debd465db
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
@@ -0,0 +1,705 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package authority
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "path"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/google/uuid"
+)
+
+const (
+ authorizationEndpoint = "https://%v/%v/oauth2/v2.0/authorize"
+ aadInstanceDiscoveryEndpoint = "https://%v/common/discovery/instance"
+ tenantDiscoveryEndpointWithRegion = "https://%s.%s/%s/v2.0/.well-known/openid-configuration"
+ regionName = "REGION_NAME"
+ defaultAPIVersion = "2021-10-01"
+ imdsEndpoint = "http://169.254.169.254/metadata/instance/compute/location?format=text&api-version=" + defaultAPIVersion
+ autoDetectRegion = "TryAutoDetect"
+ AccessTokenTypeBearer = "Bearer"
+)
+
+// These are various hosts that host AAD Instance discovery endpoints.
+const (
+ defaultHost = "login.microsoftonline.com"
+ loginMicrosoft = "login.microsoft.com"
+ loginWindows = "login.windows.net"
+ loginSTSWindows = "sts.windows.net"
+ loginMicrosoftOnline = defaultHost
+)
+
+// jsonCaller is an interface that allows us to mock the JSONCall method.
+type jsonCaller interface {
+ JSONCall(ctx context.Context, endpoint string, headers http.Header, qv url.Values, body, resp interface{}) error
+}
+
+// For backward compatibility, accept both old and new China endpoints for a transition period.
+// This list is derived from the AAD instance discovery metadata and represents all known trusted hosts
+// across different Azure clouds (Public, China, Germany, US Government, etc.)
+var aadTrustedHostList = map[string]bool{
+ "login.windows.net": true, // Microsoft Azure Worldwide - Used in validation scenarios where host is not this list
+ "login.partner.microsoftonline.cn": true, // Microsoft Azure China (new)
+ "login.chinacloudapi.cn": true, // Microsoft Azure China (legacy, backward compatibility)
+ "login.microsoftonline.de": true, // Microsoft Azure Blackforest
+ "login-us.microsoftonline.com": true, // Microsoft Azure US Government - Legacy
+ "login.microsoftonline.us": true, // Microsoft Azure US Government
+ "login.microsoftonline.com": true, // Microsoft Azure Worldwide
+ "login.microsoft.com": true,
+ "sts.windows.net": true,
+ "login.usgovcloudapi.net": true,
+}
+
+// TrustedHost checks if an AAD host is trusted/valid.
+func TrustedHost(host string) bool {
+ if _, ok := aadTrustedHostList[host]; ok {
+ return true
+ }
+ return false
+}
+
+// OAuthResponseBase is the base JSON return message for an OAuth call.
+// This is embedded in other calls to get the base fields from every response.
+type OAuthResponseBase struct {
+ Error string `json:"error"`
+ SubError string `json:"suberror"`
+ ErrorDescription string `json:"error_description"`
+ ErrorCodes []int `json:"error_codes"`
+ CorrelationID string `json:"correlation_id"`
+ Claims string `json:"claims"`
+}
+
+// TenantDiscoveryResponse is the tenant endpoints from the OpenID configuration endpoint.
+type TenantDiscoveryResponse struct {
+ OAuthResponseBase
+
+ AuthorizationEndpoint string `json:"authorization_endpoint"`
+ TokenEndpoint string `json:"token_endpoint"`
+ Issuer string `json:"issuer"`
+
+ AdditionalFields map[string]interface{}
+}
+
+// Validate validates that the response had the correct values required.
+func (r *TenantDiscoveryResponse) Validate() error {
+ switch "" {
+ case r.AuthorizationEndpoint:
+ return errors.New("TenantDiscoveryResponse: authorize endpoint was not found in the openid configuration")
+ case r.TokenEndpoint:
+ return errors.New("TenantDiscoveryResponse: token endpoint was not found in the openid configuration")
+ case r.Issuer:
+ return errors.New("TenantDiscoveryResponse: issuer was not found in the openid configuration")
+ }
+ return nil
+}
+
+// ValidateIssuerMatchesAuthority validates that the issuer in the TenantDiscoveryResponse matches the authority.
+// This is used to identity security or configuration issues in authorities and the OIDC endpoint
+func (r *TenantDiscoveryResponse) ValidateIssuerMatchesAuthority(authorityURI string, aliases map[string]bool) error {
+ if authorityURI == "" {
+ return errors.New("TenantDiscoveryResponse: empty authorityURI provided for validation")
+ }
+ if r.Issuer == "" {
+ return errors.New("TenantDiscoveryResponse: empty issuer in response")
+ }
+
+ issuerURL, err := url.Parse(r.Issuer)
+ if err != nil {
+ return fmt.Errorf("TenantDiscoveryResponse: failed to parse issuer URL: %w", err)
+ }
+ authorityURL, err := url.Parse(authorityURI)
+ if err != nil {
+ return fmt.Errorf("TenantDiscoveryResponse: failed to parse authority URL: %w", err)
+ }
+
+ // Fast path: exact scheme + host match
+ if issuerURL.Scheme == authorityURL.Scheme && issuerURL.Host == authorityURL.Host {
+ return nil
+ }
+
+ // Alias-based acceptance
+ if aliases != nil && aliases[issuerURL.Host] {
+ return nil
+ }
+
+ issuerHost := issuerURL.Host
+ authorityHost := authorityURL.Host
+
+ // Accept if issuer host is trusted
+ if TrustedHost(issuerHost) {
+ return nil
+ }
+
+ // Accept if authority is a regional variant ending with "."
+ if strings.HasSuffix(authorityHost, "."+issuerHost) {
+ return nil
+ }
+
+ return fmt.Errorf("TenantDiscoveryResponse: issuer '%s' does not match authority '%s' or any trusted/alias rule", r.Issuer, authorityURI)
+}
+
+type InstanceDiscoveryMetadata struct {
+ PreferredNetwork string `json:"preferred_network"`
+ PreferredCache string `json:"preferred_cache"`
+ Aliases []string `json:"aliases"`
+
+ AdditionalFields map[string]interface{}
+}
+
+type InstanceDiscoveryResponse struct {
+ TenantDiscoveryEndpoint string `json:"tenant_discovery_endpoint"`
+ Metadata []InstanceDiscoveryMetadata `json:"metadata"`
+
+ AdditionalFields map[string]interface{}
+}
+
+//go:generate stringer -type=AuthorizeType
+
+// AuthorizeType represents the type of token flow.
+type AuthorizeType int
+
+// These are all the types of token flows.
+const (
+ ATUnknown AuthorizeType = iota
+ ATUsernamePassword
+ ATWindowsIntegrated
+ ATAuthCode
+ ATInteractive
+ ATClientCredentials
+ ATDeviceCode
+ ATRefreshToken
+ AccountByID
+ ATOnBehalfOf
+)
+
+// These are all authority types
+const (
+ AAD = "MSSTS"
+ ADFS = "ADFS"
+ DSTS = "DSTS"
+)
+
+// DSTSTenant is referenced throughout multiple files, let us use a const in case we ever need to change it.
+const DSTSTenant = "7a433bfc-2514-4697-b467-e0933190487f"
+
+// AuthenticationScheme is an extensibility mechanism designed to be used only by Azure Arc for proof of possession access tokens.
+type AuthenticationScheme interface {
+ // Extra parameters that are added to the request to the /token endpoint.
+ TokenRequestParams() map[string]string
+ // Key ID of the public / private key pair used by the encryption algorithm, if any.
+ // Tokens obtained by authentication schemes that use this are bound to the KeyId, i.e.
+ // if a different kid is presented, the access token cannot be used.
+ KeyID() string
+ // Creates the access token that goes into an Authorization HTTP header.
+ FormatAccessToken(accessToken string) (string, error)
+ //Expected to match the token_type parameter returned by ESTS. Used to disambiguate
+ // between ATs of different types (e.g. Bearer and PoP) when loading from cache etc.
+ AccessTokenType() string
+}
+
+// default authn scheme realizing AuthenticationScheme for "Bearer" tokens
+type BearerAuthenticationScheme struct{}
+
+var bearerAuthnScheme BearerAuthenticationScheme
+
+func (ba *BearerAuthenticationScheme) TokenRequestParams() map[string]string {
+ return nil
+}
+func (ba *BearerAuthenticationScheme) KeyID() string {
+ return ""
+}
+func (ba *BearerAuthenticationScheme) FormatAccessToken(accessToken string) (string, error) {
+ return accessToken, nil
+}
+func (ba *BearerAuthenticationScheme) AccessTokenType() string {
+ return AccessTokenTypeBearer
+}
+
+// AuthParams represents the parameters used for authorization for token acquisition.
+type AuthParams struct {
+ AuthorityInfo Info
+ CorrelationID string
+ Endpoints Endpoints
+ ClientID string
+ // Redirecturi is used for auth flows that specify a redirect URI (e.g. local server for interactive auth flow).
+ Redirecturi string
+ HomeAccountID string
+ // Username is the user-name portion for username/password auth flow.
+ Username string
+ // Password is the password portion for username/password auth flow.
+ Password string
+ // Scopes is the list of scopes the user consents to.
+ Scopes []string
+ // AuthorizationType specifies the auth flow being used.
+ AuthorizationType AuthorizeType
+ // State is a random value used to prevent cross-site request forgery attacks.
+ State string
+ // CodeChallenge is derived from a code verifier and is sent in the auth request.
+ CodeChallenge string
+ // CodeChallengeMethod describes the method used to create the CodeChallenge.
+ CodeChallengeMethod string
+ // Prompt specifies the user prompt type during interactive auth.
+ Prompt string
+ // IsConfidentialClient specifies if it is a confidential client.
+ IsConfidentialClient bool
+ // SendX5C specifies if x5c claim(public key of the certificate) should be sent to STS.
+ SendX5C bool
+ // UserAssertion is the access token used to acquire token on behalf of user
+ UserAssertion string
+ // Capabilities the client will include with each token request, for example "CP1".
+ // Call [NewClientCapabilities] to construct a value for this field.
+ Capabilities ClientCapabilities
+ // Claims required for an access token to satisfy a conditional access policy
+ Claims string
+ // KnownAuthorityHosts don't require metadata discovery because they're known to the user
+ KnownAuthorityHosts []string
+ // LoginHint is a username with which to pre-populate account selection during interactive auth
+ LoginHint string
+ // DomainHint is a directive that can be used to accelerate the user to their federated IdP sign-in page
+ DomainHint string
+ // AuthnScheme is an optional scheme for formatting access tokens
+ AuthnScheme AuthenticationScheme
+ // ExtraBodyParameters are additional parameters to include in token requests.
+ // The functions are evaluated at request time to get the parameter values.
+ // These parameters are also included in the cache key.
+ ExtraBodyParameters map[string]string
+ // CacheKeyComponents are additional components to include in the cache key.
+ CacheKeyComponents map[string]string
+}
+
+// NewAuthParams creates an authorization parameters object.
+func NewAuthParams(clientID string, authorityInfo Info) AuthParams {
+ return AuthParams{
+ ClientID: clientID,
+ AuthorityInfo: authorityInfo,
+ CorrelationID: uuid.New().String(),
+ AuthnScheme: &bearerAuthnScheme,
+ }
+}
+
+// WithTenant returns a copy of the AuthParams having the specified tenant ID. If the given
+// ID is empty, the copy is identical to the original. This function returns an error in
+// several cases:
+// - ID isn't specific (for example, it's "common")
+// - ID is non-empty and the authority doesn't support tenants (for example, it's an ADFS authority)
+// - the client is configured to authenticate only Microsoft accounts via the "consumers" endpoint
+// - the resulting authority URL is invalid
+func (p AuthParams) WithTenant(ID string) (AuthParams, error) {
+ if ID == "" || ID == p.AuthorityInfo.Tenant {
+ return p, nil
+ }
+
+ var authority string
+ switch p.AuthorityInfo.AuthorityType {
+ case AAD:
+ if ID == "common" || ID == "consumers" || ID == "organizations" {
+ return p, fmt.Errorf(`tenant ID must be a specific tenant, not "%s"`, ID)
+ }
+ if p.AuthorityInfo.Tenant == "consumers" {
+ return p, errors.New(`client is configured to authenticate only personal Microsoft accounts, via the "consumers" endpoint`)
+ }
+ authority = "https://" + path.Join(p.AuthorityInfo.Host, ID)
+ case ADFS:
+ return p, errors.New("ADFS authority doesn't support tenants")
+ case DSTS:
+ return p, errors.New("dSTS authority doesn't support tenants")
+ }
+
+ info, err := NewInfoFromAuthorityURI(authority, p.AuthorityInfo.ValidateAuthority, p.AuthorityInfo.InstanceDiscoveryDisabled)
+ if err == nil {
+ info.Region = p.AuthorityInfo.Region
+ p.AuthorityInfo = info
+ }
+ return p, err
+}
+
+// MergeCapabilitiesAndClaims combines client capabilities and challenge claims into a value suitable for an authentication request's "claims" parameter.
+func (p AuthParams) MergeCapabilitiesAndClaims() (string, error) {
+ claims := p.Claims
+ if len(p.Capabilities.asMap) > 0 {
+ if claims == "" {
+ // without claims the result is simply the capabilities
+ return p.Capabilities.asJSON, nil
+ }
+ // Otherwise, merge claims and capabilties into a single JSON object.
+ // We handle the claims challenge as a map because we don't know its structure.
+ var challenge map[string]any
+ if err := json.Unmarshal([]byte(claims), &challenge); err != nil {
+ return "", fmt.Errorf(`claims must be JSON. Are they base64 encoded? json.Unmarshal returned "%v"`, err)
+ }
+ if err := merge(p.Capabilities.asMap, challenge); err != nil {
+ return "", err
+ }
+ b, err := json.Marshal(challenge)
+ if err != nil {
+ return "", err
+ }
+ claims = string(b)
+ }
+ return claims, nil
+}
+
+// merges a into b without overwriting b's values. Returns an error when a and b share a key for which either has a non-object value.
+func merge(a, b map[string]any) error {
+ for k, av := range a {
+ if bv, ok := b[k]; !ok {
+ // b doesn't contain this key => simply set it to a's value
+ b[k] = av
+ } else {
+ // b does contain this key => recursively merge a[k] into b[k], provided both are maps. If a[k] or b[k] isn't
+ // a map, return an error because merging would overwrite some value in b. Errors shouldn't occur in practice
+ // because the challenge will be from AAD, which knows the capabilities format.
+ if A, ok := av.(map[string]any); ok {
+ if B, ok := bv.(map[string]any); ok {
+ return merge(A, B)
+ } else {
+ // b[k] isn't a map
+ return errors.New("challenge claims conflict with client capabilities")
+ }
+ } else {
+ // a[k] isn't a map
+ return errors.New("challenge claims conflict with client capabilities")
+ }
+ }
+ }
+ return nil
+}
+
+// ClientCapabilities stores capabilities in the formats used by AuthParams.MergeCapabilitiesAndClaims.
+// [NewClientCapabilities] precomputes these representations because capabilities are static for the
+// lifetime of a client and are included with every authentication request i.e., these computations
+// always have the same result and would otherwise have to be repeated for every request.
+type ClientCapabilities struct {
+ // asJSON is for the common case: adding the capabilities to an auth request with no challenge claims
+ asJSON string
+ // asMap is for merging the capabilities with challenge claims
+ asMap map[string]any
+}
+
+func NewClientCapabilities(capabilities []string) (ClientCapabilities, error) {
+ c := ClientCapabilities{}
+ var err error
+ if len(capabilities) > 0 {
+ cpbs := make([]string, len(capabilities))
+ for i := 0; i < len(cpbs); i++ {
+ cpbs[i] = fmt.Sprintf(`"%s"`, capabilities[i])
+ }
+ c.asJSON = fmt.Sprintf(`{"access_token":{"xms_cc":{"values":[%s]}}}`, strings.Join(cpbs, ","))
+ // note our JSON is valid but we can't stop users breaking it with garbage like "}"
+ err = json.Unmarshal([]byte(c.asJSON), &c.asMap)
+ }
+ return c, err
+}
+
+// Info consists of information about the authority.
+type Info struct {
+ Host string
+ CanonicalAuthorityURI string
+ AuthorityType string
+ ValidateAuthority bool
+ Tenant string
+ Region string
+ InstanceDiscoveryDisabled bool
+ // InstanceDiscoveryMetadata stores the metadata from AAD instance discovery
+ InstanceDiscoveryMetadata []InstanceDiscoveryMetadata
+}
+
+// NewInfoFromAuthorityURI creates an AuthorityInfo instance from the authority URL provided.
+func NewInfoFromAuthorityURI(authority string, validateAuthority bool, instanceDiscoveryDisabled bool) (Info, error) {
+
+ cannonicalAuthority := authority
+
+ // suffix authority with / if it doesn't have one
+ if !strings.HasSuffix(cannonicalAuthority, "/") {
+ cannonicalAuthority += "/"
+ }
+
+ u, err := url.Parse(strings.ToLower(cannonicalAuthority))
+
+ if err != nil {
+ return Info{}, fmt.Errorf("couldn't parse authority url: %w", err)
+ }
+ if u.Scheme != "https" {
+ return Info{}, errors.New("authority url scheme must be https")
+ }
+
+ pathParts := strings.Split(u.EscapedPath(), "/")
+ if len(pathParts) < 3 {
+ return Info{}, errors.New(`authority must be an URL such as "https://login.microsoftonline.com/"`)
+ }
+
+ authorityType := AAD
+ tenant := pathParts[1]
+ switch tenant {
+ case "adfs":
+ authorityType = ADFS
+ case "dstsv2":
+ if len(pathParts) != 4 {
+ return Info{}, fmt.Errorf("dSTS authority must be an https URL such as https:///dstsv2/%s", DSTSTenant)
+ }
+ if pathParts[2] != DSTSTenant {
+ return Info{}, fmt.Errorf("dSTS authority only accepts a single tenant %q", DSTSTenant)
+ }
+ authorityType = DSTS
+ tenant = DSTSTenant
+ }
+
+ // u.Host includes the port, if any, which is required for private cloud deployments
+ return Info{
+ Host: u.Host,
+ CanonicalAuthorityURI: cannonicalAuthority,
+ AuthorityType: authorityType,
+ ValidateAuthority: validateAuthority,
+ Tenant: tenant,
+ InstanceDiscoveryDisabled: instanceDiscoveryDisabled,
+ }, nil
+}
+
+// Endpoints consists of the endpoints from the tenant discovery response.
+type Endpoints struct {
+ AuthorizationEndpoint string
+ TokenEndpoint string
+ selfSignedJwtAudience string
+ authorityHost string
+}
+
+// NewEndpoints creates an Endpoints object.
+func NewEndpoints(authorizationEndpoint string, tokenEndpoint string, selfSignedJwtAudience string, authorityHost string) Endpoints {
+ return Endpoints{authorizationEndpoint, tokenEndpoint, selfSignedJwtAudience, authorityHost}
+}
+
+// UserRealmAccountType refers to the type of user realm.
+type UserRealmAccountType string
+
+// These are the different types of user realms.
+const (
+ Unknown UserRealmAccountType = ""
+ Federated UserRealmAccountType = "Federated"
+ Managed UserRealmAccountType = "Managed"
+)
+
+// UserRealm is used for the username password request to determine user type
+type UserRealm struct {
+ AccountType UserRealmAccountType `json:"account_type"`
+ DomainName string `json:"domain_name"`
+ CloudInstanceName string `json:"cloud_instance_name"`
+ CloudAudienceURN string `json:"cloud_audience_urn"`
+
+ // required if accountType is Federated
+ FederationProtocol string `json:"federation_protocol"`
+ FederationMetadataURL string `json:"federation_metadata_url"`
+
+ AdditionalFields map[string]interface{}
+}
+
+func (u UserRealm) validate() error {
+ switch "" {
+ case string(u.AccountType):
+ return errors.New("the account type (Federated or Managed) is missing")
+ case u.DomainName:
+ return errors.New("domain name of user realm is missing")
+ case u.CloudInstanceName:
+ return errors.New("cloud instance name of user realm is missing")
+ case u.CloudAudienceURN:
+ return errors.New("cloud Instance URN is missing")
+ }
+
+ if u.AccountType == Federated {
+ switch "" {
+ case u.FederationProtocol:
+ return errors.New("federation protocol of user realm is missing")
+ case u.FederationMetadataURL:
+ return errors.New("federation metadata URL of user realm is missing")
+ }
+ }
+ return nil
+}
+
+// Client represents the REST calls to authority backends.
+type Client struct {
+ // Comm provides the HTTP transport client.
+ Comm jsonCaller // *comm.Client
+}
+
+func (c Client) UserRealm(ctx context.Context, authParams AuthParams) (UserRealm, error) {
+ endpoint := fmt.Sprintf("https://%s/common/UserRealm/%s", authParams.Endpoints.authorityHost, url.PathEscape(authParams.Username))
+ qv := url.Values{
+ "api-version": []string{"1.0"},
+ }
+
+ resp := UserRealm{}
+ err := c.Comm.JSONCall(
+ ctx,
+ endpoint,
+ http.Header{"client-request-id": []string{authParams.CorrelationID}},
+ qv,
+ nil,
+ &resp,
+ )
+ if err != nil {
+ return resp, err
+ }
+
+ return resp, resp.validate()
+}
+
+func (c Client) GetTenantDiscoveryResponse(ctx context.Context, openIDConfigurationEndpoint string) (TenantDiscoveryResponse, error) {
+ resp := TenantDiscoveryResponse{}
+ err := c.Comm.JSONCall(
+ ctx,
+ openIDConfigurationEndpoint,
+ http.Header{},
+ nil,
+ nil,
+ &resp,
+ )
+
+ return resp, err
+}
+
+// AADInstanceDiscovery attempts to discover a tenant endpoint (used in OIDC auth with an authorization endpoint).
+// This is done by AAD which allows for aliasing of tenants (windows.sts.net is the same as login.windows.com).
+func (c Client) AADInstanceDiscovery(ctx context.Context, authorityInfo Info) (InstanceDiscoveryResponse, error) {
+ region := ""
+ var err error
+ resp := InstanceDiscoveryResponse{}
+ if authorityInfo.Region != "" && authorityInfo.Region != autoDetectRegion {
+ region = authorityInfo.Region
+ } else if authorityInfo.Region == autoDetectRegion {
+ region = detectRegion(ctx)
+ }
+ if region != "" {
+ environment := authorityInfo.Host
+ switch environment {
+ case loginMicrosoft, loginWindows, loginSTSWindows, defaultHost:
+ environment = loginMicrosoft
+ }
+
+ resp.TenantDiscoveryEndpoint = fmt.Sprintf(tenantDiscoveryEndpointWithRegion, region, environment, authorityInfo.Tenant)
+ metadata := InstanceDiscoveryMetadata{
+ PreferredNetwork: fmt.Sprintf("%v.%v", region, authorityInfo.Host),
+ PreferredCache: authorityInfo.Host,
+ Aliases: []string{fmt.Sprintf("%v.%v", region, authorityInfo.Host), authorityInfo.Host},
+ }
+ resp.Metadata = []InstanceDiscoveryMetadata{metadata}
+ } else {
+ qv := url.Values{}
+ qv.Set("api-version", "1.1")
+ qv.Set("authorization_endpoint", fmt.Sprintf(authorizationEndpoint, authorityInfo.Host, authorityInfo.Tenant))
+
+ discoveryHost := defaultHost
+ if TrustedHost(authorityInfo.Host) {
+ discoveryHost = authorityInfo.Host
+ }
+
+ endpoint := fmt.Sprintf(aadInstanceDiscoveryEndpoint, discoveryHost)
+ err = c.Comm.JSONCall(ctx, endpoint, http.Header{}, qv, nil, &resp)
+ }
+ return resp, err
+}
+
+func detectRegion(ctx context.Context) string {
+ region := os.Getenv(regionName)
+ if region != "" {
+ region = strings.ReplaceAll(region, " ", "")
+ return strings.ToLower(region)
+ }
+ // HTTP call to IMDS endpoint to get region
+ // Refer : https://identitydivision.visualstudio.com/DevEx/_git/AuthLibrariesApiReview?path=%2FPinAuthToRegion%2FAAD%20SDK%20Proposal%20to%20Pin%20Auth%20to%20region.md&_a=preview&version=GBdev
+ // Set a 2 second timeout for this http client which only does calls to IMDS endpoint
+ client := http.Client{
+ Timeout: time.Duration(2 * time.Second),
+ }
+ req, _ := http.NewRequestWithContext(ctx, http.MethodGet, imdsEndpoint, nil)
+ req.Header.Set("Metadata", "true")
+ resp, err := client.Do(req)
+ if err == nil {
+ defer resp.Body.Close()
+ }
+ // If the request times out or there is an error, it is retried once
+ if err != nil || resp.StatusCode != http.StatusOK {
+ resp, err = client.Do(req)
+ if err != nil || resp.StatusCode != http.StatusOK {
+ return ""
+ }
+ }
+ response, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return ""
+ }
+ return string(response)
+}
+
+func (a *AuthParams) CacheKey(isAppCache bool) string {
+ if a.AuthorizationType == ATOnBehalfOf {
+ return a.AssertionHash()
+ }
+ if a.AuthorizationType == ATClientCredentials || isAppCache {
+ return a.AppKey()
+ }
+ if a.AuthorizationType == ATRefreshToken || a.AuthorizationType == AccountByID {
+ return a.HomeAccountID
+ }
+ return ""
+}
+func (a *AuthParams) AssertionHash() string {
+ hasher := sha256.New()
+ // Per documentation this never returns an error : https://pkg.go.dev/hash#pkg-types
+ _, _ = hasher.Write([]byte(a.UserAssertion))
+ sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
+ return sha
+}
+
+func (a *AuthParams) AppKey() string {
+ baseKey := a.ClientID + "_"
+ if a.AuthorityInfo.Tenant != "" {
+ baseKey += a.AuthorityInfo.Tenant
+ }
+
+ // Include extra body parameters in the cache key
+ paramHash := a.CacheExtKeyGenerator()
+ if paramHash != "" {
+ baseKey = fmt.Sprintf("%s_%s", baseKey, paramHash)
+ }
+
+ return baseKey + "_AppTokenCache"
+}
+
+// CacheExtKeyGenerator computes a hash of the Cache key components key and values
+// to include in the cache key. This ensures tokens acquired with different
+// parameters are cached separately.
+func (a *AuthParams) CacheExtKeyGenerator() string {
+ if len(a.CacheKeyComponents) == 0 {
+ return ""
+ }
+
+ // Sort keys to ensure consistent hashing
+ keys := make([]string, 0, len(a.CacheKeyComponents))
+ for k := range a.CacheKeyComponents {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ // Create a string by concatenating key+value pairs
+ keyStr := ""
+ for _, key := range keys {
+ // Append key followed by its value with no separator
+ keyStr += key + a.CacheKeyComponents[key]
+ }
+
+ hash := sha256.Sum256([]byte(keyStr))
+ return strings.ToLower(base64.RawURLEncoding.EncodeToString(hash[:]))
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authorizetype_string.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authorizetype_string.go
new file mode 100644
index 000000000..10039773b
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authorizetype_string.go
@@ -0,0 +1,30 @@
+// Code generated by "stringer -type=AuthorizeType"; DO NOT EDIT.
+
+package authority
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[ATUnknown-0]
+ _ = x[ATUsernamePassword-1]
+ _ = x[ATWindowsIntegrated-2]
+ _ = x[ATAuthCode-3]
+ _ = x[ATInteractive-4]
+ _ = x[ATClientCredentials-5]
+ _ = x[ATDeviceCode-6]
+ _ = x[ATRefreshToken-7]
+}
+
+const _AuthorizeType_name = "ATUnknownATUsernamePasswordATWindowsIntegratedATAuthCodeATInteractiveATClientCredentialsATDeviceCodeATRefreshToken"
+
+var _AuthorizeType_index = [...]uint8{0, 9, 27, 46, 56, 69, 88, 100, 114}
+
+func (i AuthorizeType) String() string {
+ if i < 0 || i >= AuthorizeType(len(_AuthorizeType_index)-1) {
+ return "AuthorizeType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _AuthorizeType_name[_AuthorizeType_index[i]:_AuthorizeType_index[i+1]]
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go
new file mode 100644
index 000000000..790680366
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/comm.go
@@ -0,0 +1,319 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// Package comm provides helpers for communicating with HTTP backends.
+package comm
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/google/uuid"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
+ customJSON "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version"
+)
+
+// HTTPClient represents an HTTP client.
+// It's usually an *http.Client from the standard library.
+type HTTPClient interface {
+ // Do sends an HTTP request and returns an HTTP response.
+ Do(req *http.Request) (*http.Response, error)
+
+ // CloseIdleConnections closes any idle connections in a "keep-alive" state.
+ CloseIdleConnections()
+}
+
+// Client provides a wrapper to our *http.Client that handles compression and serialization needs.
+type Client struct {
+ client HTTPClient
+}
+
+// New returns a new Client object.
+func New(httpClient HTTPClient) *Client {
+ if httpClient == nil {
+ panic("http.Client cannot == nil")
+ }
+
+ return &Client{client: httpClient}
+}
+
+// JSONCall connects to the REST endpoint passing the HTTP query values, headers and JSON conversion
+// of body in the HTTP body. It automatically handles compression and decompression with gzip. The response is JSON
+// unmarshalled into resp. resp must be a pointer to a struct. If the body struct contains a field called
+// "AdditionalFields" we use a custom marshal/unmarshal engine.
+func (c *Client) JSONCall(ctx context.Context, endpoint string, headers http.Header, qv url.Values, body, resp interface{}) error {
+ if qv == nil {
+ qv = url.Values{}
+ }
+
+ v := reflect.ValueOf(resp)
+ if err := c.checkResp(v); err != nil {
+ return err
+ }
+
+ // Choose a JSON marshal/unmarshal depending on if we have AdditionalFields attribute.
+ var marshal = json.Marshal
+ var unmarshal = json.Unmarshal
+ if _, ok := v.Elem().Type().FieldByName("AdditionalFields"); ok {
+ marshal = customJSON.Marshal
+ unmarshal = customJSON.Unmarshal
+ }
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s?%s", endpoint, qv.Encode()), nil)
+ if err != nil {
+ return fmt.Errorf("could not create request: %w", err)
+ }
+
+ addStdHeaders(headers)
+ req.Header = headers
+
+ if body != nil {
+ // Note: In case your wondering why we are not gzip encoding....
+ // I'm not sure if these various services support gzip on send.
+ headers.Add("Content-Type", "application/json; charset=utf-8")
+ data, err := marshal(body)
+ if err != nil {
+ return fmt.Errorf("bug: conn.Call(): could not marshal the body object: %w", err)
+ }
+ req.Body = io.NopCloser(bytes.NewBuffer(data))
+ req.Method = http.MethodPost
+ }
+
+ data, err := c.do(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ if resp != nil {
+ if err := unmarshal(data, resp); err != nil {
+ return errors.InvalidJsonErr{Err: fmt.Errorf("json decode error: %w\njson message bytes were: %s", err, string(data))}
+ }
+ }
+ return nil
+}
+
+// XMLCall connects to an endpoint and decodes the XML response into resp. This is used when
+// sending application/xml . If sending XML via SOAP, use SOAPCall().
+func (c *Client) XMLCall(ctx context.Context, endpoint string, headers http.Header, qv url.Values, resp interface{}) error {
+ if err := c.checkResp(reflect.ValueOf(resp)); err != nil {
+ return err
+ }
+
+ if qv == nil {
+ qv = url.Values{}
+ }
+
+ u, err := url.Parse(endpoint)
+ if err != nil {
+ return fmt.Errorf("could not parse path URL(%s): %w", endpoint, err)
+ }
+ u.RawQuery = qv.Encode()
+
+ headers.Set("Content-Type", "application/xml; charset=utf-8") // This was not set in he original Mex(), but...
+ addStdHeaders(headers)
+
+ return c.xmlCall(ctx, u, headers, "", resp)
+}
+
+// SOAPCall returns the SOAP message given an endpoint, action, body of the request and the response object to marshal into.
+func (c *Client) SOAPCall(ctx context.Context, endpoint, action string, headers http.Header, qv url.Values, body string, resp interface{}) error {
+ if body == "" {
+ return fmt.Errorf("cannot make a SOAP call with body set to empty string")
+ }
+
+ if err := c.checkResp(reflect.ValueOf(resp)); err != nil {
+ return err
+ }
+
+ if qv == nil {
+ qv = url.Values{}
+ }
+
+ u, err := url.Parse(endpoint)
+ if err != nil {
+ return fmt.Errorf("could not parse path URL(%s): %w", endpoint, err)
+ }
+ u.RawQuery = qv.Encode()
+
+ headers.Set("Content-Type", "application/soap+xml; charset=utf-8")
+ headers.Set("SOAPAction", action)
+ addStdHeaders(headers)
+
+ return c.xmlCall(ctx, u, headers, body, resp)
+}
+
+// xmlCall sends an XML in body and decodes into resp. This simply does the transport and relies on
+// an upper level call to set things such as SOAP parameters and Content-Type, if required.
+func (c *Client) xmlCall(ctx context.Context, u *url.URL, headers http.Header, body string, resp interface{}) error {
+ req := &http.Request{Method: http.MethodGet, URL: u, Header: headers}
+
+ if len(body) > 0 {
+ req.Method = http.MethodPost
+ req.Body = io.NopCloser(strings.NewReader(body))
+ }
+
+ data, err := c.do(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ return xml.Unmarshal(data, resp)
+}
+
+// URLFormCall is used to make a call where we need to send application/x-www-form-urlencoded data
+// to the backend and receive JSON back. qv will be encoded into the request body.
+func (c *Client) URLFormCall(ctx context.Context, endpoint string, qv url.Values, resp interface{}) error {
+ if len(qv) == 0 {
+ return fmt.Errorf("URLFormCall() requires qv to have non-zero length")
+ }
+
+ if err := c.checkResp(reflect.ValueOf(resp)); err != nil {
+ return err
+ }
+
+ u, err := url.Parse(endpoint)
+ if err != nil {
+ return fmt.Errorf("could not parse path URL(%s): %w", endpoint, err)
+ }
+
+ headers := http.Header{}
+ headers.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
+ addStdHeaders(headers)
+
+ enc := qv.Encode()
+
+ req := &http.Request{
+ Method: http.MethodPost,
+ URL: u,
+ Header: headers,
+ ContentLength: int64(len(enc)),
+ Body: io.NopCloser(strings.NewReader(enc)),
+ GetBody: func() (io.ReadCloser, error) {
+ return io.NopCloser(strings.NewReader(enc)), nil
+ },
+ }
+
+ data, err := c.do(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ v := reflect.ValueOf(resp)
+ if err := c.checkResp(v); err != nil {
+ return err
+ }
+
+ var unmarshal = json.Unmarshal
+ if _, ok := v.Elem().Type().FieldByName("AdditionalFields"); ok {
+ unmarshal = customJSON.Unmarshal
+ }
+ if resp != nil {
+ if err := unmarshal(data, resp); err != nil {
+ return errors.InvalidJsonErr{Err: fmt.Errorf("json decode error: %w\nraw message was: %s", err, string(data))}
+ }
+ }
+ return nil
+}
+
+// do makes the HTTP call to the server and returns the contents of the body.
+func (c *Client) do(ctx context.Context, req *http.Request) ([]byte, error) {
+ if _, ok := ctx.Deadline(); !ok {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
+ defer cancel()
+ }
+ req = req.WithContext(ctx)
+
+ reply, err := c.client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("server response error:\n %w", err)
+ }
+ defer reply.Body.Close()
+
+ data, err := c.readBody(reply)
+ if err != nil {
+ return nil, fmt.Errorf("could not read the body of an HTTP Response: %w", err)
+ }
+ reply.Body = io.NopCloser(bytes.NewBuffer(data))
+
+ // NOTE: This doesn't happen immediately after the call so that we can get an error message
+ // from the server and include it in our error.
+ switch reply.StatusCode {
+ case 200, 201:
+ default:
+ sd := strings.TrimSpace(string(data))
+ if sd != "" {
+ // We probably have the error in the body.
+ return nil, errors.CallErr{
+ Req: req,
+ Resp: reply,
+ Err: fmt.Errorf("http call(%s)(%s) error: reply status code was %d:\n%s", req.URL.String(), req.Method, reply.StatusCode, sd),
+ }
+ }
+ return nil, errors.CallErr{
+ Req: req,
+ Resp: reply,
+ Err: fmt.Errorf("http call(%s)(%s) error: reply status code was %d", req.URL.String(), req.Method, reply.StatusCode),
+ }
+ }
+
+ return data, nil
+}
+
+// checkResp checks a response object o make sure it is a pointer to a struct.
+func (c *Client) checkResp(v reflect.Value) error {
+ if v.Kind() != reflect.Ptr {
+ return fmt.Errorf("bug: resp argument must a *struct, was %T", v.Interface())
+ }
+ v = v.Elem()
+ if v.Kind() != reflect.Struct {
+ return fmt.Errorf("bug: resp argument must be a *struct, was %T", v.Interface())
+ }
+ return nil
+}
+
+// readBody reads the body out of an *http.Response. It supports gzip encoded responses.
+func (c *Client) readBody(resp *http.Response) ([]byte, error) {
+ var reader io.Reader = resp.Body
+ switch resp.Header.Get("Content-Encoding") {
+ case "":
+ // Do nothing
+ case "gzip":
+ reader = gzipDecompress(resp.Body)
+ default:
+ return nil, fmt.Errorf("bug: comm.Client.JSONCall(): content was send with unsupported content-encoding %s", resp.Header.Get("Content-Encoding"))
+ }
+ return io.ReadAll(reader)
+}
+
+var testID string
+
+// addStdHeaders adds the standard headers we use on all calls.
+func addStdHeaders(headers http.Header) http.Header {
+ headers.Set("Accept-Encoding", "gzip")
+ // So that I can have a static id for tests.
+ if testID != "" {
+ headers.Set("client-request-id", testID)
+ headers.Set("Return-Client-Request-Id", "false")
+ } else {
+ headers.Set("client-request-id", uuid.New().String())
+ headers.Set("Return-Client-Request-Id", "false")
+ }
+ headers.Set("x-client-sku", "MSAL.Go")
+ headers.Set("x-client-os", runtime.GOOS)
+ headers.Set("x-client-cpu", runtime.GOARCH)
+ headers.Set("x-client-ver", version.Version)
+ return headers
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/compress.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/compress.go
new file mode 100644
index 000000000..4d3dbfcf0
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm/compress.go
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package comm
+
+import (
+ "compress/gzip"
+ "io"
+)
+
+func gzipDecompress(r io.Reader) io.Reader {
+ gzipReader, _ := gzip.NewReader(r)
+
+ pipeOut, pipeIn := io.Pipe()
+ go func() {
+ // decompression bomb would have to come from Azure services.
+ // If we want to limit, we should do that in comm.do().
+ _, err := io.Copy(pipeIn, gzipReader) //nolint
+ if err != nil {
+ // don't need the error.
+ pipeIn.CloseWithError(err) //nolint
+ gzipReader.Close()
+ return
+ }
+ if err := gzipReader.Close(); err != nil {
+ // don't need the error.
+ pipeIn.CloseWithError(err) //nolint
+ return
+ }
+ pipeIn.Close()
+ }()
+ return pipeOut
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant/grant.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant/grant.go
new file mode 100644
index 000000000..b628f61ac
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant/grant.go
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// Package grant holds types of grants issued by authorization services.
+package grant
+
+const (
+ Password = "password"
+ JWT = "urn:ietf:params:oauth:grant-type:jwt-bearer"
+ SAMLV1 = "urn:ietf:params:oauth:grant-type:saml1_1-bearer"
+ SAMLV2 = "urn:ietf:params:oauth:grant-type:saml2-bearer"
+ DeviceCode = "device_code"
+ AuthCode = "authorization_code"
+ RefreshToken = "refresh_token"
+ ClientCredential = "client_credentials"
+ ClientAssertion = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
+)
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/ops.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/ops.go
new file mode 100644
index 000000000..1f9c543fa
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/ops.go
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/*
+Package ops provides operations to various backend services using REST clients.
+
+The REST type provides several clients that can be used to communicate to backends.
+Usage is simple:
+
+ rest := ops.New()
+
+ // Creates an authority client and calls the UserRealm() method.
+ userRealm, err := rest.Authority().UserRealm(ctx, authParameters)
+ if err != nil {
+ // Do something
+ }
+*/
+package ops
+
+import (
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust"
+)
+
+// HTTPClient represents an HTTP client.
+// It's usually an *http.Client from the standard library.
+type HTTPClient = comm.HTTPClient
+
+// REST provides REST clients for communicating with various backends used by MSAL.
+type REST struct {
+ client *comm.Client
+}
+
+// New is the constructor for REST.
+func New(httpClient HTTPClient) *REST {
+ return &REST{client: comm.New(httpClient)}
+}
+
+// Authority returns a client for querying information about various authorities.
+func (r *REST) Authority() authority.Client {
+ return authority.Client{Comm: r.client}
+}
+
+// AccessTokens returns a client that can be used to get various access tokens for
+// authorization purposes.
+func (r *REST) AccessTokens() accesstokens.Client {
+ return accesstokens.Client{Comm: r.client}
+}
+
+// WSTrust provides access to various metadata in a WSTrust service. This data can
+// be used to gain tokens based on SAML data using the client provided by AccessTokens().
+func (r *REST) WSTrust() wstrust.Client {
+ return wstrust.Client{Comm: r.client}
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/endpointtype_string.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/endpointtype_string.go
new file mode 100644
index 000000000..a2bb6278a
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/endpointtype_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type=endpointType"; DO NOT EDIT.
+
+package defs
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[etUnknown-0]
+ _ = x[etUsernamePassword-1]
+ _ = x[etWindowsTransport-2]
+}
+
+const _endpointType_name = "etUnknownetUsernamePasswordetWindowsTransport"
+
+var _endpointType_index = [...]uint8{0, 9, 27, 45}
+
+func (i endpointType) String() string {
+ if i < 0 || i >= endpointType(len(_endpointType_index)-1) {
+ return "endpointType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _endpointType_name[_endpointType_index[i]:_endpointType_index[i+1]]
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/mex_document_definitions.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/mex_document_definitions.go
new file mode 100644
index 000000000..649727002
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/mex_document_definitions.go
@@ -0,0 +1,394 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package defs
+
+import "encoding/xml"
+
+type Definitions struct {
+ XMLName xml.Name `xml:"definitions"`
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ TargetNamespace string `xml:"targetNamespace,attr"`
+ WSDL string `xml:"wsdl,attr"`
+ XSD string `xml:"xsd,attr"`
+ T string `xml:"t,attr"`
+ SOAPENC string `xml:"soapenc,attr"`
+ SOAP string `xml:"soap,attr"`
+ TNS string `xml:"tns,attr"`
+ MSC string `xml:"msc,attr"`
+ WSAM string `xml:"wsam,attr"`
+ SOAP12 string `xml:"soap12,attr"`
+ WSA10 string `xml:"wsa10,attr"`
+ WSA string `xml:"wsa,attr"`
+ WSAW string `xml:"wsaw,attr"`
+ WSX string `xml:"wsx,attr"`
+ WSAP string `xml:"wsap,attr"`
+ WSU string `xml:"wsu,attr"`
+ Trust string `xml:"trust,attr"`
+ WSP string `xml:"wsp,attr"`
+ Policy []Policy `xml:"Policy"`
+ Types Types `xml:"types"`
+ Message []Message `xml:"message"`
+ PortType []PortType `xml:"portType"`
+ Binding []Binding `xml:"binding"`
+ Service Service `xml:"service"`
+}
+
+type Policy struct {
+ Text string `xml:",chardata"`
+ ID string `xml:"Id,attr"`
+ ExactlyOne ExactlyOne `xml:"ExactlyOne"`
+}
+
+type ExactlyOne struct {
+ Text string `xml:",chardata"`
+ All All `xml:"All"`
+}
+
+type All struct {
+ Text string `xml:",chardata"`
+ NegotiateAuthentication NegotiateAuthentication `xml:"NegotiateAuthentication"`
+ TransportBinding TransportBinding `xml:"TransportBinding"`
+ UsingAddressing Text `xml:"UsingAddressing"`
+ EndorsingSupportingTokens EndorsingSupportingTokens `xml:"EndorsingSupportingTokens"`
+ WSS11 WSS11 `xml:"Wss11"`
+ Trust10 Trust10 `xml:"Trust10"`
+ SignedSupportingTokens SignedSupportingTokens `xml:"SignedSupportingTokens"`
+ Trust13 WSTrust13 `xml:"Trust13"`
+ SignedEncryptedSupportingTokens SignedEncryptedSupportingTokens `xml:"SignedEncryptedSupportingTokens"`
+}
+
+type NegotiateAuthentication struct {
+ Text string `xml:",chardata"`
+ HTTP string `xml:"http,attr"`
+ XMLName xml.Name
+}
+
+type TransportBinding struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy TransportBindingPolicy `xml:"Policy"`
+}
+
+type TransportBindingPolicy struct {
+ Text string `xml:",chardata"`
+ TransportToken TransportToken `xml:"TransportToken"`
+ AlgorithmSuite AlgorithmSuite `xml:"AlgorithmSuite"`
+ Layout Layout `xml:"Layout"`
+ IncludeTimestamp Text `xml:"IncludeTimestamp"`
+}
+
+type TransportToken struct {
+ Text string `xml:",chardata"`
+ Policy TransportTokenPolicy `xml:"Policy"`
+}
+
+type TransportTokenPolicy struct {
+ Text string `xml:",chardata"`
+ HTTPSToken HTTPSToken `xml:"HttpsToken"`
+}
+
+type HTTPSToken struct {
+ Text string `xml:",chardata"`
+ RequireClientCertificate string `xml:"RequireClientCertificate,attr"`
+}
+
+type AlgorithmSuite struct {
+ Text string `xml:",chardata"`
+ Policy AlgorithmSuitePolicy `xml:"Policy"`
+}
+
+type AlgorithmSuitePolicy struct {
+ Text string `xml:",chardata"`
+ Basic256 Text `xml:"Basic256"`
+ Basic128 Text `xml:"Basic128"`
+}
+
+type Layout struct {
+ Text string `xml:",chardata"`
+ Policy LayoutPolicy `xml:"Policy"`
+}
+
+type LayoutPolicy struct {
+ Text string `xml:",chardata"`
+ Strict Text `xml:"Strict"`
+}
+
+type EndorsingSupportingTokens struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy EndorsingSupportingTokensPolicy `xml:"Policy"`
+}
+
+type EndorsingSupportingTokensPolicy struct {
+ Text string `xml:",chardata"`
+ X509Token X509Token `xml:"X509Token"`
+ RSAToken RSAToken `xml:"RsaToken"`
+ SignedParts SignedParts `xml:"SignedParts"`
+ KerberosToken KerberosToken `xml:"KerberosToken"`
+ IssuedToken IssuedToken `xml:"IssuedToken"`
+ KeyValueToken KeyValueToken `xml:"KeyValueToken"`
+}
+
+type X509Token struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ Policy X509TokenPolicy `xml:"Policy"`
+}
+
+type X509TokenPolicy struct {
+ Text string `xml:",chardata"`
+ RequireThumbprintReference Text `xml:"RequireThumbprintReference"`
+ WSSX509V3Token10 Text `xml:"WssX509V3Token10"`
+}
+
+type RSAToken struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ Optional string `xml:"Optional,attr"`
+ MSSP string `xml:"mssp,attr"`
+}
+
+type SignedParts struct {
+ Text string `xml:",chardata"`
+ Header SignedPartsHeader `xml:"Header"`
+}
+
+type SignedPartsHeader struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"Name,attr"`
+ Namespace string `xml:"Namespace,attr"`
+}
+
+type KerberosToken struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ Policy KerberosTokenPolicy `xml:"Policy"`
+}
+
+type KerberosTokenPolicy struct {
+ Text string `xml:",chardata"`
+ WSSGSSKerberosV5ApReqToken11 Text `xml:"WssGssKerberosV5ApReqToken11"`
+}
+
+type IssuedToken struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ RequestSecurityTokenTemplate RequestSecurityTokenTemplate `xml:"RequestSecurityTokenTemplate"`
+ Policy IssuedTokenPolicy `xml:"Policy"`
+}
+
+type RequestSecurityTokenTemplate struct {
+ Text string `xml:",chardata"`
+ KeyType Text `xml:"KeyType"`
+ EncryptWith Text `xml:"EncryptWith"`
+ SignatureAlgorithm Text `xml:"SignatureAlgorithm"`
+ CanonicalizationAlgorithm Text `xml:"CanonicalizationAlgorithm"`
+ EncryptionAlgorithm Text `xml:"EncryptionAlgorithm"`
+ KeySize Text `xml:"KeySize"`
+ KeyWrapAlgorithm Text `xml:"KeyWrapAlgorithm"`
+}
+
+type IssuedTokenPolicy struct {
+ Text string `xml:",chardata"`
+ RequireInternalReference Text `xml:"RequireInternalReference"`
+}
+
+type KeyValueToken struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ Optional string `xml:"Optional,attr"`
+}
+
+type WSS11 struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy Wss11Policy `xml:"Policy"`
+}
+
+type Wss11Policy struct {
+ Text string `xml:",chardata"`
+ MustSupportRefThumbprint Text `xml:"MustSupportRefThumbprint"`
+}
+
+type Trust10 struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy Trust10Policy `xml:"Policy"`
+}
+
+type Trust10Policy struct {
+ Text string `xml:",chardata"`
+ MustSupportIssuedTokens Text `xml:"MustSupportIssuedTokens"`
+ RequireClientEntropy Text `xml:"RequireClientEntropy"`
+ RequireServerEntropy Text `xml:"RequireServerEntropy"`
+}
+
+type SignedSupportingTokens struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy SupportingTokensPolicy `xml:"Policy"`
+}
+
+type SupportingTokensPolicy struct {
+ Text string `xml:",chardata"`
+ UsernameToken UsernameToken `xml:"UsernameToken"`
+}
+type UsernameToken struct {
+ Text string `xml:",chardata"`
+ IncludeToken string `xml:"IncludeToken,attr"`
+ Policy UsernameTokenPolicy `xml:"Policy"`
+}
+
+type UsernameTokenPolicy struct {
+ Text string `xml:",chardata"`
+ WSSUsernameToken10 WSSUsernameToken10 `xml:"WssUsernameToken10"`
+}
+
+type WSSUsernameToken10 struct {
+ Text string `xml:",chardata"`
+ XMLName xml.Name
+}
+
+type WSTrust13 struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy WSTrust13Policy `xml:"Policy"`
+}
+
+type WSTrust13Policy struct {
+ Text string `xml:",chardata"`
+ MustSupportIssuedTokens Text `xml:"MustSupportIssuedTokens"`
+ RequireClientEntropy Text `xml:"RequireClientEntropy"`
+ RequireServerEntropy Text `xml:"RequireServerEntropy"`
+}
+
+type SignedEncryptedSupportingTokens struct {
+ Text string `xml:",chardata"`
+ SP string `xml:"sp,attr"`
+ Policy SupportingTokensPolicy `xml:"Policy"`
+}
+
+type Types struct {
+ Text string `xml:",chardata"`
+ Schema Schema `xml:"schema"`
+}
+
+type Schema struct {
+ Text string `xml:",chardata"`
+ TargetNamespace string `xml:"targetNamespace,attr"`
+ Import []Import `xml:"import"`
+}
+
+type Import struct {
+ Text string `xml:",chardata"`
+ SchemaLocation string `xml:"schemaLocation,attr"`
+ Namespace string `xml:"namespace,attr"`
+}
+
+type Message struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Part Part `xml:"part"`
+}
+
+type Part struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Element string `xml:"element,attr"`
+}
+
+type PortType struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Operation Operation `xml:"operation"`
+}
+
+type Operation struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Input OperationIO `xml:"input"`
+ Output OperationIO `xml:"output"`
+}
+
+type OperationIO struct {
+ Text string `xml:",chardata"`
+ Action string `xml:"Action,attr"`
+ Message string `xml:"message,attr"`
+ Body OperationIOBody `xml:"body"`
+}
+
+type OperationIOBody struct {
+ Text string `xml:",chardata"`
+ Use string `xml:"use,attr"`
+}
+
+type Binding struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ PolicyReference PolicyReference `xml:"PolicyReference"`
+ Binding DefinitionsBinding `xml:"binding"`
+ Operation BindingOperation `xml:"operation"`
+}
+
+type PolicyReference struct {
+ Text string `xml:",chardata"`
+ URI string `xml:"URI,attr"`
+}
+
+type DefinitionsBinding struct {
+ Text string `xml:",chardata"`
+ Transport string `xml:"transport,attr"`
+}
+
+type BindingOperation struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Operation BindingOperationOperation `xml:"operation"`
+ Input BindingOperationIO `xml:"input"`
+ Output BindingOperationIO `xml:"output"`
+}
+
+type BindingOperationOperation struct {
+ Text string `xml:",chardata"`
+ SoapAction string `xml:"soapAction,attr"`
+ Style string `xml:"style,attr"`
+}
+
+type BindingOperationIO struct {
+ Text string `xml:",chardata"`
+ Body OperationIOBody `xml:"body"`
+}
+
+type Service struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Port []Port `xml:"port"`
+}
+
+type Port struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name,attr"`
+ Binding string `xml:"binding,attr"`
+ Address Address `xml:"address"`
+ EndpointReference PortEndpointReference `xml:"EndpointReference"`
+}
+
+type Address struct {
+ Text string `xml:",chardata"`
+ Location string `xml:"location,attr"`
+}
+
+type PortEndpointReference struct {
+ Text string `xml:",chardata"`
+ Address Text `xml:"Address"`
+ Identity Identity `xml:"Identity"`
+}
+
+type Identity struct {
+ Text string `xml:",chardata"`
+ XMLNS string `xml:"xmlns,attr"`
+ SPN Text `xml:"Spn"`
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/saml_assertion_definitions.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/saml_assertion_definitions.go
new file mode 100644
index 000000000..7d0725565
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/saml_assertion_definitions.go
@@ -0,0 +1,230 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package defs
+
+import "encoding/xml"
+
+// TODO(msal): Someone (and it ain't gonna be me) needs to document these attributes or
+// at the least put a link to RFC.
+
+type SAMLDefinitions struct {
+ XMLName xml.Name `xml:"Envelope"`
+ Text string `xml:",chardata"`
+ S string `xml:"s,attr"`
+ A string `xml:"a,attr"`
+ U string `xml:"u,attr"`
+ Header Header `xml:"Header"`
+ Body Body `xml:"Body"`
+}
+
+type Header struct {
+ Text string `xml:",chardata"`
+ Action Action `xml:"Action"`
+ Security Security `xml:"Security"`
+}
+
+type Action struct {
+ Text string `xml:",chardata"`
+ MustUnderstand string `xml:"mustUnderstand,attr"`
+}
+
+type Security struct {
+ Text string `xml:",chardata"`
+ MustUnderstand string `xml:"mustUnderstand,attr"`
+ O string `xml:"o,attr"`
+ Timestamp Timestamp `xml:"Timestamp"`
+}
+
+type Timestamp struct {
+ Text string `xml:",chardata"`
+ ID string `xml:"Id,attr"`
+ Created Text `xml:"Created"`
+ Expires Text `xml:"Expires"`
+}
+
+type Text struct {
+ Text string `xml:",chardata"`
+}
+
+type Body struct {
+ Text string `xml:",chardata"`
+ RequestSecurityTokenResponseCollection RequestSecurityTokenResponseCollection `xml:"RequestSecurityTokenResponseCollection"`
+}
+
+type RequestSecurityTokenResponseCollection struct {
+ Text string `xml:",chardata"`
+ Trust string `xml:"trust,attr"`
+ RequestSecurityTokenResponse []RequestSecurityTokenResponse `xml:"RequestSecurityTokenResponse"`
+}
+
+type RequestSecurityTokenResponse struct {
+ Text string `xml:",chardata"`
+ Lifetime Lifetime `xml:"Lifetime"`
+ AppliesTo AppliesTo `xml:"AppliesTo"`
+ RequestedSecurityToken RequestedSecurityToken `xml:"RequestedSecurityToken"`
+ RequestedAttachedReference RequestedAttachedReference `xml:"RequestedAttachedReference"`
+ RequestedUnattachedReference RequestedUnattachedReference `xml:"RequestedUnattachedReference"`
+ TokenType Text `xml:"TokenType"`
+ RequestType Text `xml:"RequestType"`
+ KeyType Text `xml:"KeyType"`
+}
+
+type Lifetime struct {
+ Text string `xml:",chardata"`
+ Created WSUTimestamp `xml:"Created"`
+ Expires WSUTimestamp `xml:"Expires"`
+}
+
+type WSUTimestamp struct {
+ Text string `xml:",chardata"`
+ Wsu string `xml:"wsu,attr"`
+}
+
+type AppliesTo struct {
+ Text string `xml:",chardata"`
+ Wsp string `xml:"wsp,attr"`
+ EndpointReference EndpointReference `xml:"EndpointReference"`
+}
+
+type EndpointReference struct {
+ Text string `xml:",chardata"`
+ Wsa string `xml:"wsa,attr"`
+ Address Text `xml:"Address"`
+}
+
+type RequestedSecurityToken struct {
+ Text string `xml:",chardata"`
+ AssertionRawXML string `xml:",innerxml"`
+ Assertion Assertion `xml:"Assertion"`
+}
+
+type Assertion struct {
+ XMLName xml.Name // Normally its `xml:"Assertion"`, but I think they want to capture the xmlns
+ Text string `xml:",chardata"`
+ MajorVersion string `xml:"MajorVersion,attr"`
+ MinorVersion string `xml:"MinorVersion,attr"`
+ AssertionID string `xml:"AssertionID,attr"`
+ Issuer string `xml:"Issuer,attr"`
+ IssueInstant string `xml:"IssueInstant,attr"`
+ Saml string `xml:"saml,attr"`
+ Conditions Conditions `xml:"Conditions"`
+ AttributeStatement AttributeStatement `xml:"AttributeStatement"`
+ AuthenticationStatement AuthenticationStatement `xml:"AuthenticationStatement"`
+ Signature Signature `xml:"Signature"`
+}
+
+type Conditions struct {
+ Text string `xml:",chardata"`
+ NotBefore string `xml:"NotBefore,attr"`
+ NotOnOrAfter string `xml:"NotOnOrAfter,attr"`
+ AudienceRestrictionCondition AudienceRestrictionCondition `xml:"AudienceRestrictionCondition"`
+}
+
+type AudienceRestrictionCondition struct {
+ Text string `xml:",chardata"`
+ Audience Text `xml:"Audience"`
+}
+
+type AttributeStatement struct {
+ Text string `xml:",chardata"`
+ Subject Subject `xml:"Subject"`
+ Attribute []Attribute `xml:"Attribute"`
+}
+
+type Subject struct {
+ Text string `xml:",chardata"`
+ NameIdentifier NameIdentifier `xml:"NameIdentifier"`
+ SubjectConfirmation SubjectConfirmation `xml:"SubjectConfirmation"`
+}
+
+type NameIdentifier struct {
+ Text string `xml:",chardata"`
+ Format string `xml:"Format,attr"`
+}
+
+type SubjectConfirmation struct {
+ Text string `xml:",chardata"`
+ ConfirmationMethod Text `xml:"ConfirmationMethod"`
+}
+
+type Attribute struct {
+ Text string `xml:",chardata"`
+ AttributeName string `xml:"AttributeName,attr"`
+ AttributeNamespace string `xml:"AttributeNamespace,attr"`
+ AttributeValue Text `xml:"AttributeValue"`
+}
+
+type AuthenticationStatement struct {
+ Text string `xml:",chardata"`
+ AuthenticationMethod string `xml:"AuthenticationMethod,attr"`
+ AuthenticationInstant string `xml:"AuthenticationInstant,attr"`
+ Subject Subject `xml:"Subject"`
+}
+
+type Signature struct {
+ Text string `xml:",chardata"`
+ Ds string `xml:"ds,attr"`
+ SignedInfo SignedInfo `xml:"SignedInfo"`
+ SignatureValue Text `xml:"SignatureValue"`
+ KeyInfo KeyInfo `xml:"KeyInfo"`
+}
+
+type SignedInfo struct {
+ Text string `xml:",chardata"`
+ CanonicalizationMethod Method `xml:"CanonicalizationMethod"`
+ SignatureMethod Method `xml:"SignatureMethod"`
+ Reference Reference `xml:"Reference"`
+}
+
+type Method struct {
+ Text string `xml:",chardata"`
+ Algorithm string `xml:"Algorithm,attr"`
+}
+
+type Reference struct {
+ Text string `xml:",chardata"`
+ URI string `xml:"URI,attr"`
+ Transforms Transforms `xml:"Transforms"`
+ DigestMethod Method `xml:"DigestMethod"`
+ DigestValue Text `xml:"DigestValue"`
+}
+
+type Transforms struct {
+ Text string `xml:",chardata"`
+ Transform []Method `xml:"Transform"`
+}
+
+type KeyInfo struct {
+ Text string `xml:",chardata"`
+ Xmlns string `xml:"xmlns,attr"`
+ X509Data X509Data `xml:"X509Data"`
+}
+
+type X509Data struct {
+ Text string `xml:",chardata"`
+ X509Certificate Text `xml:"X509Certificate"`
+}
+
+type RequestedAttachedReference struct {
+ Text string `xml:",chardata"`
+ SecurityTokenReference SecurityTokenReference `xml:"SecurityTokenReference"`
+}
+
+type SecurityTokenReference struct {
+ Text string `xml:",chardata"`
+ TokenType string `xml:"TokenType,attr"`
+ O string `xml:"o,attr"`
+ K string `xml:"k,attr"`
+ KeyIdentifier KeyIdentifier `xml:"KeyIdentifier"`
+}
+
+type KeyIdentifier struct {
+ Text string `xml:",chardata"`
+ ValueType string `xml:"ValueType,attr"`
+}
+
+type RequestedUnattachedReference struct {
+ Text string `xml:",chardata"`
+ SecurityTokenReference SecurityTokenReference `xml:"SecurityTokenReference"`
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/version_string.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/version_string.go
new file mode 100644
index 000000000..6fe5efa8a
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/version_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type=Version"; DO NOT EDIT.
+
+package defs
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[TrustUnknown-0]
+ _ = x[Trust2005-1]
+ _ = x[Trust13-2]
+}
+
+const _Version_name = "TrustUnknownTrust2005Trust13"
+
+var _Version_index = [...]uint8{0, 12, 21, 28}
+
+func (i Version) String() string {
+ if i < 0 || i >= Version(len(_Version_index)-1) {
+ return "Version(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Version_name[_Version_index[i]:_Version_index[i+1]]
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_endpoint.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_endpoint.go
new file mode 100644
index 000000000..8fad5efb5
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_endpoint.go
@@ -0,0 +1,199 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package defs
+
+import (
+ "encoding/xml"
+ "fmt"
+ "time"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ uuid "github.com/google/uuid"
+)
+
+//go:generate stringer -type=Version
+
+type Version int
+
+const (
+ TrustUnknown Version = iota
+ Trust2005
+ Trust13
+)
+
+// Endpoint represents a WSTrust endpoint.
+type Endpoint struct {
+ // Version is the version of the endpoint.
+ Version Version
+ // URL is the URL of the endpoint.
+ URL string
+}
+
+type wsTrustTokenRequestEnvelope struct {
+ XMLName xml.Name `xml:"s:Envelope"`
+ Text string `xml:",chardata"`
+ S string `xml:"xmlns:s,attr"`
+ Wsa string `xml:"xmlns:wsa,attr"`
+ Wsu string `xml:"xmlns:wsu,attr"`
+ Header struct {
+ Text string `xml:",chardata"`
+ Action struct {
+ Text string `xml:",chardata"`
+ MustUnderstand string `xml:"s:mustUnderstand,attr"`
+ } `xml:"wsa:Action"`
+ MessageID struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsa:messageID"`
+ ReplyTo struct {
+ Text string `xml:",chardata"`
+ Address struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsa:Address"`
+ } `xml:"wsa:ReplyTo"`
+ To struct {
+ Text string `xml:",chardata"`
+ MustUnderstand string `xml:"s:mustUnderstand,attr"`
+ } `xml:"wsa:To"`
+ Security struct {
+ Text string `xml:",chardata"`
+ MustUnderstand string `xml:"s:mustUnderstand,attr"`
+ Wsse string `xml:"xmlns:wsse,attr"`
+ Timestamp struct {
+ Text string `xml:",chardata"`
+ ID string `xml:"wsu:Id,attr"`
+ Created struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsu:Created"`
+ Expires struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsu:Expires"`
+ } `xml:"wsu:Timestamp"`
+ UsernameToken struct {
+ Text string `xml:",chardata"`
+ ID string `xml:"wsu:Id,attr"`
+ Username struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsse:Username"`
+ Password struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsse:Password"`
+ } `xml:"wsse:UsernameToken"`
+ } `xml:"wsse:Security"`
+ } `xml:"s:Header"`
+ Body struct {
+ Text string `xml:",chardata"`
+ RequestSecurityToken struct {
+ Text string `xml:",chardata"`
+ Wst string `xml:"xmlns:wst,attr"`
+ AppliesTo struct {
+ Text string `xml:",chardata"`
+ Wsp string `xml:"xmlns:wsp,attr"`
+ EndpointReference struct {
+ Text string `xml:",chardata"`
+ Address struct {
+ Text string `xml:",chardata"`
+ } `xml:"wsa:Address"`
+ } `xml:"wsa:EndpointReference"`
+ } `xml:"wsp:AppliesTo"`
+ KeyType struct {
+ Text string `xml:",chardata"`
+ } `xml:"wst:KeyType"`
+ RequestType struct {
+ Text string `xml:",chardata"`
+ } `xml:"wst:RequestType"`
+ } `xml:"wst:RequestSecurityToken"`
+ } `xml:"s:Body"`
+}
+
+func buildTimeString(t time.Time) string {
+ // Golang time formats are weird: https://stackoverflow.com/questions/20234104/how-to-format-current-time-using-a-yyyymmddhhmmss-format
+ return t.Format("2006-01-02T15:04:05.000Z")
+}
+
+func (wte *Endpoint) buildTokenRequestMessage(authType authority.AuthorizeType, cloudAudienceURN string, username string, password string) (string, error) {
+ var soapAction string
+ var trustNamespace string
+ var keyType string
+ var requestType string
+
+ createdTime := time.Now().UTC()
+ expiresTime := createdTime.Add(10 * time.Minute)
+
+ switch wte.Version {
+ case Trust2005:
+ soapAction = trust2005Spec
+ trustNamespace = "http://schemas.xmlsoap.org/ws/2005/02/trust"
+ keyType = "http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey"
+ requestType = "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue"
+ case Trust13:
+ soapAction = trust13Spec
+ trustNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512"
+ keyType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer"
+ requestType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue"
+ default:
+ return "", fmt.Errorf("buildTokenRequestMessage had Version == %q, which is not recognized", wte.Version)
+ }
+
+ var envelope wsTrustTokenRequestEnvelope
+
+ messageUUID := uuid.New()
+
+ envelope.S = "http://www.w3.org/2003/05/soap-envelope"
+ envelope.Wsa = "http://www.w3.org/2005/08/addressing"
+ envelope.Wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+
+ envelope.Header.Action.MustUnderstand = "1"
+ envelope.Header.Action.Text = soapAction
+ envelope.Header.MessageID.Text = "urn:uuid:" + messageUUID.String()
+ envelope.Header.ReplyTo.Address.Text = "http://www.w3.org/2005/08/addressing/anonymous"
+ envelope.Header.To.MustUnderstand = "1"
+ envelope.Header.To.Text = wte.URL
+
+ switch authType {
+ case authority.ATUnknown:
+ return "", fmt.Errorf("buildTokenRequestMessage had no authority type(%v)", authType)
+ case authority.ATUsernamePassword:
+ endpointUUID := uuid.New()
+
+ var trustID string
+ if wte.Version == Trust2005 {
+ trustID = "UnPwSecTok2005-" + endpointUUID.String()
+ } else {
+ trustID = "UnPwSecTok13-" + endpointUUID.String()
+ }
+
+ envelope.Header.Security.MustUnderstand = "1"
+ envelope.Header.Security.Wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+ envelope.Header.Security.Timestamp.ID = "MSATimeStamp"
+ envelope.Header.Security.Timestamp.Created.Text = buildTimeString(createdTime)
+ envelope.Header.Security.Timestamp.Expires.Text = buildTimeString(expiresTime)
+ envelope.Header.Security.UsernameToken.ID = trustID
+ envelope.Header.Security.UsernameToken.Username.Text = username
+ envelope.Header.Security.UsernameToken.Password.Text = password
+ default:
+ // This is just to note that we don't do anything for other cases.
+ // We aren't missing anything I know of.
+ }
+
+ envelope.Body.RequestSecurityToken.Wst = trustNamespace
+ envelope.Body.RequestSecurityToken.AppliesTo.Wsp = "http://schemas.xmlsoap.org/ws/2004/09/policy"
+ envelope.Body.RequestSecurityToken.AppliesTo.EndpointReference.Address.Text = cloudAudienceURN
+ envelope.Body.RequestSecurityToken.KeyType.Text = keyType
+ envelope.Body.RequestSecurityToken.RequestType.Text = requestType
+
+ output, err := xml.Marshal(envelope)
+ if err != nil {
+ return "", err
+ }
+
+ return string(output), nil
+}
+
+func (wte *Endpoint) BuildTokenRequestMessageWIA(cloudAudienceURN string) (string, error) {
+ return wte.buildTokenRequestMessage(authority.ATWindowsIntegrated, cloudAudienceURN, "", "")
+}
+
+func (wte *Endpoint) BuildTokenRequestMessageUsernamePassword(cloudAudienceURN string, username string, password string) (string, error) {
+ return wte.buildTokenRequestMessage(authority.ATUsernamePassword, cloudAudienceURN, username, password)
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_mex_document.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_mex_document.go
new file mode 100644
index 000000000..e3d19886e
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs/wstrust_mex_document.go
@@ -0,0 +1,159 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package defs
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+//go:generate stringer -type=endpointType
+
+type endpointType int
+
+const (
+ etUnknown endpointType = iota
+ etUsernamePassword
+ etWindowsTransport
+)
+
+type wsEndpointData struct {
+ Version Version
+ EndpointType endpointType
+}
+
+const trust13Spec string = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"
+const trust2005Spec string = "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue"
+
+type MexDocument struct {
+ UsernamePasswordEndpoint Endpoint
+ WindowsTransportEndpoint Endpoint
+ policies map[string]endpointType
+ bindings map[string]wsEndpointData
+}
+
+func updateEndpoint(cached *Endpoint, found Endpoint) {
+ if cached == nil || cached.Version == TrustUnknown {
+ *cached = found
+ return
+ }
+ if (*cached).Version == Trust2005 && found.Version == Trust13 {
+ *cached = found
+ return
+ }
+}
+
+// TODO(msal): Someone needs to write tests for everything below.
+
+// NewFromDef creates a new MexDocument.
+func NewFromDef(defs Definitions) (MexDocument, error) {
+ policies, err := policies(defs)
+ if err != nil {
+ return MexDocument{}, err
+ }
+
+ bindings, err := bindings(defs, policies)
+ if err != nil {
+ return MexDocument{}, err
+ }
+
+ userPass, windows, err := endpoints(defs, bindings)
+ if err != nil {
+ return MexDocument{}, err
+ }
+
+ return MexDocument{
+ UsernamePasswordEndpoint: userPass,
+ WindowsTransportEndpoint: windows,
+ policies: policies,
+ bindings: bindings,
+ }, nil
+}
+
+func policies(defs Definitions) (map[string]endpointType, error) {
+ policies := make(map[string]endpointType, len(defs.Policy))
+
+ for _, policy := range defs.Policy {
+ if policy.ExactlyOne.All.NegotiateAuthentication.XMLName.Local != "" {
+ if policy.ExactlyOne.All.TransportBinding.SP != "" && policy.ID != "" {
+ policies["#"+policy.ID] = etWindowsTransport
+ }
+ }
+
+ if policy.ExactlyOne.All.SignedEncryptedSupportingTokens.Policy.UsernameToken.Policy.WSSUsernameToken10.XMLName.Local != "" {
+ if policy.ExactlyOne.All.TransportBinding.SP != "" && policy.ID != "" {
+ policies["#"+policy.ID] = etUsernamePassword
+ }
+ }
+ if policy.ExactlyOne.All.SignedSupportingTokens.Policy.UsernameToken.Policy.WSSUsernameToken10.XMLName.Local != "" {
+ if policy.ExactlyOne.All.TransportBinding.SP != "" && policy.ID != "" {
+ policies["#"+policy.ID] = etUsernamePassword
+ }
+ }
+ }
+
+ if len(policies) == 0 {
+ return policies, errors.New("no policies for mex document")
+ }
+
+ return policies, nil
+}
+
+func bindings(defs Definitions, policies map[string]endpointType) (map[string]wsEndpointData, error) {
+ bindings := make(map[string]wsEndpointData, len(defs.Binding))
+
+ for _, binding := range defs.Binding {
+ policyName := binding.PolicyReference.URI
+ transport := binding.Binding.Transport
+
+ if transport == "http://schemas.xmlsoap.org/soap/http" {
+ if policy, ok := policies[policyName]; ok {
+ bindingName := binding.Name
+ specVersion := binding.Operation.Operation.SoapAction
+
+ if specVersion == trust13Spec {
+ bindings[bindingName] = wsEndpointData{Trust13, policy}
+ } else if specVersion == trust2005Spec {
+ bindings[bindingName] = wsEndpointData{Trust2005, policy}
+ } else {
+ return nil, errors.New("found unknown spec version in mex document")
+ }
+ }
+ }
+ }
+ return bindings, nil
+}
+
+func endpoints(defs Definitions, bindings map[string]wsEndpointData) (userPass, windows Endpoint, err error) {
+ for _, port := range defs.Service.Port {
+ bindingName := port.Binding
+
+ index := strings.Index(bindingName, ":")
+ if index != -1 {
+ bindingName = bindingName[index+1:]
+ }
+
+ if binding, ok := bindings[bindingName]; ok {
+ url := strings.TrimSpace(port.EndpointReference.Address.Text)
+ if url == "" {
+ return Endpoint{}, Endpoint{}, fmt.Errorf("MexDocument cannot have blank URL endpoint")
+ }
+ if binding.Version == TrustUnknown {
+ return Endpoint{}, Endpoint{}, fmt.Errorf("endpoint version unknown")
+ }
+ endpoint := Endpoint{Version: binding.Version, URL: url}
+
+ switch binding.EndpointType {
+ case etUsernamePassword:
+ updateEndpoint(&userPass, endpoint)
+ case etWindowsTransport:
+ updateEndpoint(&windows, endpoint)
+ default:
+ return Endpoint{}, Endpoint{}, errors.New("found unknown port type in MEX document")
+ }
+ }
+ }
+ return userPass, windows, nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/wstrust.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/wstrust.go
new file mode 100644
index 000000000..47cd4c692
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/wstrust.go
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/*
+Package wstrust provides a client for communicating with a WSTrust (https://en.wikipedia.org/wiki/WS-Trust#:~:text=WS%2DTrust%20is%20a%20WS,in%20a%20secure%20message%20exchange.)
+for the purposes of extracting metadata from the service. This data can be used to acquire
+tokens using the accesstokens.Client.GetAccessTokenFromSamlGrant() call.
+*/
+package wstrust
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs"
+)
+
+type xmlCaller interface {
+ XMLCall(ctx context.Context, endpoint string, headers http.Header, qv url.Values, resp interface{}) error
+ SOAPCall(ctx context.Context, endpoint, action string, headers http.Header, qv url.Values, body string, resp interface{}) error
+}
+
+type SamlTokenInfo struct {
+ AssertionType string // Should be either constants SAMLV1Grant or SAMLV2Grant.
+ Assertion string
+}
+
+// Client represents the REST calls to get tokens from token generator backends.
+type Client struct {
+ // Comm provides the HTTP transport client.
+ Comm xmlCaller
+}
+
+// TODO(msal): This allows me to call Mex without having a real Def file on line 45.
+// This would fail because policies() would not find a policy. This is easy enough to
+// fix in test data, but.... Definitions is defined with built in structs. That needs
+// to be pulled apart and until then I have this hack in.
+var newFromDef = defs.NewFromDef
+
+// Mex provides metadata about a wstrust service.
+func (c Client) Mex(ctx context.Context, federationMetadataURL string) (defs.MexDocument, error) {
+ resp := defs.Definitions{}
+ err := c.Comm.XMLCall(
+ ctx,
+ federationMetadataURL,
+ http.Header{},
+ nil,
+ &resp,
+ )
+ if err != nil {
+ return defs.MexDocument{}, err
+ }
+
+ return newFromDef(resp)
+}
+
+const (
+ SoapActionDefault = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"
+
+ // Note: Commented out because this action is not supported. It was in the original code
+ // but only used in a switch where it errored. Since there was only one value, a default
+ // worked better. However, buildTokenRequestMessage() had 2005 support. I'm not actually
+ // sure what's going on here. It like we have half support. For now this is here just
+ // for documentation purposes in case we are going to add support.
+ //
+ // SoapActionWSTrust2005 = "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue"
+)
+
+// SAMLTokenInfo provides SAML information that is used to generate a SAML token.
+func (c Client) SAMLTokenInfo(ctx context.Context, authParameters authority.AuthParams, cloudAudienceURN string, endpoint defs.Endpoint) (SamlTokenInfo, error) {
+ var wsTrustRequestMessage string
+ var err error
+
+ switch authParameters.AuthorizationType {
+ case authority.ATWindowsIntegrated:
+ wsTrustRequestMessage, err = endpoint.BuildTokenRequestMessageWIA(cloudAudienceURN)
+ if err != nil {
+ return SamlTokenInfo{}, err
+ }
+ case authority.ATUsernamePassword:
+ wsTrustRequestMessage, err = endpoint.BuildTokenRequestMessageUsernamePassword(
+ cloudAudienceURN, authParameters.Username, authParameters.Password)
+ if err != nil {
+ return SamlTokenInfo{}, err
+ }
+ default:
+ return SamlTokenInfo{}, fmt.Errorf("unknown auth type %v", authParameters.AuthorizationType)
+ }
+
+ var soapAction string
+ switch endpoint.Version {
+ case defs.Trust13:
+ soapAction = SoapActionDefault
+ case defs.Trust2005:
+ return SamlTokenInfo{}, errors.New("WS Trust 2005 support is not implemented")
+ default:
+ return SamlTokenInfo{}, fmt.Errorf("the SOAP endpoint for a wstrust call had an invalid version: %v", endpoint.Version)
+ }
+
+ resp := defs.SAMLDefinitions{}
+ err = c.Comm.SOAPCall(ctx, endpoint.URL, soapAction, http.Header{}, nil, wsTrustRequestMessage, &resp)
+ if err != nil {
+ return SamlTokenInfo{}, err
+ }
+
+ return c.samlAssertion(resp)
+}
+
+const (
+ samlv1Assertion = "urn:oasis:names:tc:SAML:1.0:assertion"
+ samlv2Assertion = "urn:oasis:names:tc:SAML:2.0:assertion"
+)
+
+func (c Client) samlAssertion(def defs.SAMLDefinitions) (SamlTokenInfo, error) {
+ for _, tokenResponse := range def.Body.RequestSecurityTokenResponseCollection.RequestSecurityTokenResponse {
+ token := tokenResponse.RequestedSecurityToken
+ if token.Assertion.XMLName.Local != "" {
+ assertion := token.AssertionRawXML
+
+ samlVersion := token.Assertion.Saml
+ switch samlVersion {
+ case samlv1Assertion:
+ return SamlTokenInfo{AssertionType: grant.SAMLV1, Assertion: assertion}, nil
+ case samlv2Assertion:
+ return SamlTokenInfo{AssertionType: grant.SAMLV2, Assertion: assertion}, nil
+ }
+ return SamlTokenInfo{}, fmt.Errorf("couldn't parse SAML assertion, version unknown: %q", samlVersion)
+ }
+ }
+ return SamlTokenInfo{}, errors.New("unknown WS-Trust version")
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go
new file mode 100644
index 000000000..d220a9946
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/resolvers.go
@@ -0,0 +1,164 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// TODO(msal): Write some tests. The original code this came from didn't have tests and I'm too
+// tired at this point to do it. It, like many other *Manager code I found was broken because
+// they didn't have mutex protection.
+
+package oauth
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+)
+
+type cacheEntry struct {
+ Endpoints authority.Endpoints
+ ValidForDomainsInList map[string]bool
+ // Aliases stores host aliases from instance discovery for quick lookup
+ Aliases map[string]bool
+}
+
+func createcacheEntry(endpoints authority.Endpoints) cacheEntry {
+ return cacheEntry{endpoints, map[string]bool{}, map[string]bool{}}
+}
+
+// AuthorityEndpoint retrieves endpoints from an authority for auth and token acquisition.
+type authorityEndpoint struct {
+ rest *ops.REST
+
+ mu sync.Mutex
+ cache map[string]cacheEntry
+}
+
+// newAuthorityEndpoint is the constructor for AuthorityEndpoint.
+func newAuthorityEndpoint(rest *ops.REST) *authorityEndpoint {
+ m := &authorityEndpoint{rest: rest, cache: map[string]cacheEntry{}}
+ return m
+}
+
+// ResolveEndpoints gets the authorization and token endpoints and creates an AuthorityEndpoints instance
+func (m *authorityEndpoint) ResolveEndpoints(ctx context.Context, authorityInfo authority.Info, userPrincipalName string) (authority.Endpoints, error) {
+
+ if endpoints, found := m.cachedEndpoints(authorityInfo, userPrincipalName); found {
+ return endpoints, nil
+ }
+
+ endpoint, err := m.openIDConfigurationEndpoint(ctx, authorityInfo)
+ if err != nil {
+ return authority.Endpoints{}, err
+ }
+
+ resp, err := m.rest.Authority().GetTenantDiscoveryResponse(ctx, endpoint)
+ if err != nil {
+ return authority.Endpoints{}, err
+ }
+ if err := resp.Validate(); err != nil {
+ return authority.Endpoints{}, fmt.Errorf("ResolveEndpoints(): %w", err)
+ }
+
+ tenant := authorityInfo.Tenant
+
+ endpoints := authority.NewEndpoints(
+ strings.Replace(resp.AuthorizationEndpoint, "{tenant}", tenant, -1),
+ strings.Replace(resp.TokenEndpoint, "{tenant}", tenant, -1),
+ strings.Replace(resp.Issuer, "{tenant}", tenant, -1),
+ authorityInfo.Host)
+
+ m.addCachedEndpoints(authorityInfo, userPrincipalName, endpoints)
+
+ if err := resp.ValidateIssuerMatchesAuthority(authorityInfo.CanonicalAuthorityURI,
+ m.cache[authorityInfo.CanonicalAuthorityURI].Aliases); err != nil {
+ return authority.Endpoints{}, fmt.Errorf("ResolveEndpoints(): %w", err)
+ }
+
+ return endpoints, nil
+}
+
+// cachedEndpoints returns the cached endpoints if they exist. If not, we return false.
+func (m *authorityEndpoint) cachedEndpoints(authorityInfo authority.Info, userPrincipalName string) (authority.Endpoints, bool) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if cacheEntry, ok := m.cache[authorityInfo.CanonicalAuthorityURI]; ok {
+ if authorityInfo.AuthorityType == authority.ADFS {
+ domain, err := adfsDomainFromUpn(userPrincipalName)
+ if err == nil {
+ if _, ok := cacheEntry.ValidForDomainsInList[domain]; ok {
+ return cacheEntry.Endpoints, true
+ }
+ }
+ }
+ return cacheEntry.Endpoints, true
+ }
+ return authority.Endpoints{}, false
+}
+
+func (m *authorityEndpoint) addCachedEndpoints(authorityInfo authority.Info, userPrincipalName string, endpoints authority.Endpoints) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ updatedCacheEntry := createcacheEntry(endpoints)
+
+ if authorityInfo.AuthorityType == authority.ADFS {
+ // Since we're here, we've made a call to the backend. We want to ensure we're caching
+ // the latest values from the server.
+ if cacheEntry, ok := m.cache[authorityInfo.CanonicalAuthorityURI]; ok {
+ for k := range cacheEntry.ValidForDomainsInList {
+ updatedCacheEntry.ValidForDomainsInList[k] = true
+ }
+ }
+ domain, err := adfsDomainFromUpn(userPrincipalName)
+ if err == nil {
+ updatedCacheEntry.ValidForDomainsInList[domain] = true
+ }
+ }
+
+ // Extract aliases from instance discovery metadata and add to cache
+ for _, metadata := range authorityInfo.InstanceDiscoveryMetadata {
+ for _, alias := range metadata.Aliases {
+ updatedCacheEntry.Aliases[alias] = true
+ }
+ }
+
+ m.cache[authorityInfo.CanonicalAuthorityURI] = updatedCacheEntry
+}
+
+func (m *authorityEndpoint) openIDConfigurationEndpoint(ctx context.Context, authorityInfo authority.Info) (string, error) {
+ if authorityInfo.AuthorityType == authority.ADFS {
+ return fmt.Sprintf("https://%s/adfs/.well-known/openid-configuration", authorityInfo.Host), nil
+ } else if authorityInfo.AuthorityType == authority.DSTS {
+ return fmt.Sprintf("https://%s/dstsv2/%s/v2.0/.well-known/openid-configuration", authorityInfo.Host, authority.DSTSTenant), nil
+
+ } else if authorityInfo.ValidateAuthority && !authority.TrustedHost(authorityInfo.Host) {
+ resp, err := m.rest.Authority().AADInstanceDiscovery(ctx, authorityInfo)
+ if err != nil {
+ return "", err
+ }
+ authorityInfo.InstanceDiscoveryMetadata = resp.Metadata
+ return resp.TenantDiscoveryEndpoint, nil
+ } else if authorityInfo.Region != "" {
+ resp, err := m.rest.Authority().AADInstanceDiscovery(ctx, authorityInfo)
+ if err != nil {
+ return "", err
+ }
+ authorityInfo.InstanceDiscoveryMetadata = resp.Metadata
+ return resp.TenantDiscoveryEndpoint, nil
+ }
+
+ return authorityInfo.CanonicalAuthorityURI + "v2.0/.well-known/openid-configuration", nil
+}
+
+func adfsDomainFromUpn(userPrincipalName string) (string, error) {
+ parts := strings.Split(userPrincipalName, "@")
+ if len(parts) < 2 {
+ return "", errors.New("no @ present in user principal name")
+ }
+ return parts[1], nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/options/options.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/options/options.go
new file mode 100644
index 000000000..4561d72db
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/options/options.go
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package options
+
+import (
+ "errors"
+ "fmt"
+)
+
+// CallOption implements an optional argument to a method call. See
+// https://blog.devgenius.io/go-call-option-that-can-be-used-with-multiple-methods-6c81734f3dbe
+// for an explanation of the usage pattern.
+type CallOption interface {
+ Do(any) error
+ callOption()
+}
+
+// ApplyOptions applies all the callOptions to options. options must be a pointer to a struct and
+// callOptions must be a list of objects that implement CallOption.
+func ApplyOptions[O, C any](options O, callOptions []C) error {
+ for _, o := range callOptions {
+ if t, ok := any(o).(CallOption); !ok {
+ return fmt.Errorf("unexpected option type %T", o)
+ } else if err := t.Do(options); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// NewCallOption returns a new CallOption whose Do() method calls function "f".
+func NewCallOption(f func(any) error) CallOption {
+ if f == nil {
+ // This isn't a practical concern because only an MSAL maintainer can get
+ // us here, by implementing a do-nothing option. But if someone does that,
+ // the below ensures the method invoked with the option returns an error.
+ return callOption(func(any) error {
+ return errors.New("invalid option: missing implementation")
+ })
+ }
+ return callOption(f)
+}
+
+// callOption is an adapter for a function to a CallOption
+type callOption func(any) error
+
+func (c callOption) Do(a any) error {
+ return c(a)
+}
+
+func (callOption) callOption() {}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared/shared.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared/shared.go
new file mode 100644
index 000000000..d8ab71356
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared/shared.go
@@ -0,0 +1,72 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package shared
+
+import (
+ "net/http"
+ "reflect"
+ "strings"
+)
+
+const (
+ // CacheKeySeparator is used in creating the keys of the cache.
+ CacheKeySeparator = "-"
+)
+
+type Account struct {
+ HomeAccountID string `json:"home_account_id,omitempty"`
+ Environment string `json:"environment,omitempty"`
+ Realm string `json:"realm,omitempty"`
+ LocalAccountID string `json:"local_account_id,omitempty"`
+ AuthorityType string `json:"authority_type,omitempty"`
+ PreferredUsername string `json:"username,omitempty"`
+ GivenName string `json:"given_name,omitempty"`
+ FamilyName string `json:"family_name,omitempty"`
+ MiddleName string `json:"middle_name,omitempty"`
+ Name string `json:"name,omitempty"`
+ AlternativeID string `json:"alternative_account_id,omitempty"`
+ RawClientInfo string `json:"client_info,omitempty"`
+ UserAssertionHash string `json:"user_assertion_hash,omitempty"`
+
+ AdditionalFields map[string]interface{}
+}
+
+// NewAccount creates an account.
+func NewAccount(homeAccountID, env, realm, localAccountID, authorityType, username string) Account {
+ return Account{
+ HomeAccountID: homeAccountID,
+ Environment: env,
+ Realm: realm,
+ LocalAccountID: localAccountID,
+ AuthorityType: authorityType,
+ PreferredUsername: username,
+ }
+}
+
+// Key creates the key for storing accounts in the cache.
+func (acc Account) Key() string {
+ key := strings.Join([]string{acc.HomeAccountID, acc.Environment, acc.Realm}, CacheKeySeparator)
+ return strings.ToLower(key)
+}
+
+// IsZero checks the zero value of account.
+func (acc Account) IsZero() bool {
+ v := reflect.ValueOf(acc)
+ for i := 0; i < v.NumField(); i++ {
+ field := v.Field(i)
+ if !field.IsZero() {
+ switch field.Kind() {
+ case reflect.Map, reflect.Slice:
+ if field.Len() == 0 {
+ continue
+ }
+ }
+ return false
+ }
+ }
+ return true
+}
+
+// DefaultClient is our default shared HTTP client.
+var DefaultClient = &http.Client{}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version/version.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version/version.go
new file mode 100644
index 000000000..5e551abc8
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version/version.go
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// Package version keeps the version number of the client package.
+package version
+
+// Version is the version of this client package that is communicated to the server.
+const Version = "1.4.2"
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/azure_ml.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/azure_ml.go
new file mode 100644
index 000000000..d7cffc295
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/azure_ml.go
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package managedidentity
+
+import (
+ "context"
+ "net/http"
+ "os"
+)
+
+func createAzureMLAuthRequest(ctx context.Context, id ID, resource string) (*http.Request, error) {
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, os.Getenv(msiEndpointEnvVar), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("secret", os.Getenv(msiSecretEnvVar))
+ q := req.URL.Query()
+ q.Set(apiVersionQueryParameterName, azureMLAPIVersion)
+ q.Set(resourceQueryParameterName, resource)
+ q.Set("clientid", os.Getenv("DEFAULT_IDENTITY_CLIENT_ID"))
+ if cid, ok := id.(UserAssignedClientID); ok {
+ q.Set("clientid", string(cid))
+ }
+ req.URL.RawQuery = q.Encode()
+ return req, nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/cloud_shell.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/cloud_shell.go
new file mode 100644
index 000000000..be9a0bca3
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/cloud_shell.go
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package managedidentity
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+)
+
+func createCloudShellAuthRequest(ctx context.Context, resource string) (*http.Request, error) {
+ msiEndpoint := os.Getenv(msiEndpointEnvVar)
+ msiEndpointParsed, err := url.Parse(msiEndpoint)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse %q: %s", msiEndpoint, err)
+ }
+
+ data := url.Values{}
+ data.Set(resourceQueryParameterName, resource)
+ msiDataEncoded := data.Encode()
+ body := io.NopCloser(strings.NewReader(msiDataEncoded))
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, msiEndpointParsed.String(), body)
+ if err != nil {
+ return nil, fmt.Errorf("error creating http request %s", err)
+ }
+
+ req.Header.Set(metaHTTPHeaderName, "true")
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ return req, nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/managedidentity.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/managedidentity.go
new file mode 100644
index 000000000..ca3de4325
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/managedidentity.go
@@ -0,0 +1,717 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/*
+Package managedidentity provides a client for retrieval of Managed Identity applications.
+The Managed Identity Client is used to acquire a token for managed identity assigned to
+an azure resource such as Azure function, app service, virtual machine, etc. to acquire a token
+without using credentials.
+*/
+package managedidentity
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync/atomic"
+ "time"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared"
+)
+
+// AuthResult contains the results of one token acquisition operation.
+// For details see https://aka.ms/msal-net-authenticationresult
+type AuthResult = base.AuthResult
+
+type TokenSource = base.TokenSource
+
+const (
+ TokenSourceIdentityProvider = base.TokenSourceIdentityProvider
+ TokenSourceCache = base.TokenSourceCache
+)
+
+const (
+ // DefaultToIMDS indicates that the source is defaulted to IMDS when no environment variables are set.
+ DefaultToIMDS Source = "DefaultToIMDS"
+ AzureArc Source = "AzureArc"
+ ServiceFabric Source = "ServiceFabric"
+ CloudShell Source = "CloudShell"
+ AzureML Source = "AzureML"
+ AppService Source = "AppService"
+
+ // General request query parameter names
+ metaHTTPHeaderName = "Metadata"
+ apiVersionQueryParameterName = "api-version"
+ resourceQueryParameterName = "resource"
+ wwwAuthenticateHeaderName = "www-authenticate"
+
+ // UAMI query parameter name
+ miQueryParameterClientId = "client_id"
+ miQueryParameterObjectId = "object_id"
+ miQueryParameterPrincipalId = "principal_id"
+ miQueryParameterResourceIdIMDS = "msi_res_id"
+ miQueryParameterResourceId = "mi_res_id"
+
+ // IMDS
+ imdsDefaultEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
+ imdsAPIVersion = "2018-02-01"
+ systemAssignedManagedIdentity = "system_assigned_managed_identity"
+
+ // Azure Arc
+ azureArcEndpoint = "http://127.0.0.1:40342/metadata/identity/oauth2/token"
+ azureArcAPIVersion = "2020-06-01"
+ azureArcFileExtension = ".key"
+ azureArcMaxFileSizeBytes int64 = 4096
+ linuxTokenPath = "/var/opt/azcmagent/tokens" // #nosec G101
+ linuxHimdsPath = "/opt/azcmagent/bin/himds"
+ azureConnectedMachine = "AzureConnectedMachineAgent"
+ himdsExecutableName = "himds.exe"
+ tokenName = "Tokens"
+
+ // App Service
+ appServiceAPIVersion = "2019-08-01"
+
+ // AzureML
+ azureMLAPIVersion = "2017-09-01"
+ // Service Fabric
+ serviceFabricAPIVersion = "2019-07-01-preview"
+
+ // Environment Variables
+ identityEndpointEnvVar = "IDENTITY_ENDPOINT"
+ identityHeaderEnvVar = "IDENTITY_HEADER"
+ azurePodIdentityAuthorityHostEnvVar = "AZURE_POD_IDENTITY_AUTHORITY_HOST"
+ imdsEndVar = "IMDS_ENDPOINT"
+ msiEndpointEnvVar = "MSI_ENDPOINT"
+ msiSecretEnvVar = "MSI_SECRET"
+ identityServerThumbprintEnvVar = "IDENTITY_SERVER_THUMBPRINT"
+
+ defaultRetryCount = 3
+)
+
+var retryCodesForIMDS = []int{
+ http.StatusNotFound, // 404
+ http.StatusGone, // 410
+ http.StatusTooManyRequests, // 429
+ http.StatusInternalServerError, // 500
+ http.StatusNotImplemented, // 501
+ http.StatusBadGateway, // 502
+ http.StatusServiceUnavailable, // 503
+ http.StatusGatewayTimeout, // 504
+ http.StatusHTTPVersionNotSupported, // 505
+ http.StatusVariantAlsoNegotiates, // 506
+ http.StatusInsufficientStorage, // 507
+ http.StatusLoopDetected, // 508
+ http.StatusNotExtended, // 510
+ http.StatusNetworkAuthenticationRequired, // 511
+}
+
+var retryStatusCodes = []int{
+ http.StatusRequestTimeout, // 408
+ http.StatusTooManyRequests, // 429
+ http.StatusInternalServerError, // 500
+ http.StatusBadGateway, // 502
+ http.StatusServiceUnavailable, // 503
+ http.StatusGatewayTimeout, // 504
+}
+
+var getAzureArcPlatformPath = func(platform string) string {
+ switch platform {
+ case "windows":
+ return filepath.Join(os.Getenv("ProgramData"), azureConnectedMachine, tokenName)
+ case "linux":
+ return linuxTokenPath
+ default:
+ return ""
+ }
+}
+
+var getAzureArcHimdsFilePath = func(platform string) string {
+ switch platform {
+ case "windows":
+ return filepath.Join(os.Getenv("ProgramData"), azureConnectedMachine, himdsExecutableName)
+ case "linux":
+ return linuxHimdsPath
+ default:
+ return ""
+ }
+}
+
+type Source string
+
+type ID interface {
+ value() string
+}
+
+type systemAssignedValue string // its private for a reason to make the input consistent.
+type UserAssignedClientID string
+type UserAssignedObjectID string
+type UserAssignedResourceID string
+
+func (s systemAssignedValue) value() string { return string(s) }
+func (c UserAssignedClientID) value() string { return string(c) }
+func (o UserAssignedObjectID) value() string { return string(o) }
+func (r UserAssignedResourceID) value() string { return string(r) }
+func SystemAssigned() ID {
+ return systemAssignedValue(systemAssignedManagedIdentity)
+}
+
+// cache never uses the client because instance discovery is always disabled.
+var cacheManager *storage.Manager = storage.New(nil)
+
+type Client struct {
+ httpClient ops.HTTPClient
+ miType ID
+ source Source
+ authParams authority.AuthParams
+ retryPolicyEnabled bool
+ canRefresh *atomic.Value
+}
+
+type AcquireTokenOptions struct {
+ claims string
+}
+
+type ClientOption func(*Client)
+
+type AcquireTokenOption func(o *AcquireTokenOptions)
+
+// WithClaims sets additional claims to request for the token, such as those required by token revocation or conditional access policies.
+// Use this option when Azure AD returned a claims challenge for a prior request. The argument must be decoded.
+func WithClaims(claims string) AcquireTokenOption {
+ return func(o *AcquireTokenOptions) {
+ o.claims = claims
+ }
+}
+
+// WithHTTPClient allows for a custom HTTP client to be set.
+func WithHTTPClient(httpClient ops.HTTPClient) ClientOption {
+ return func(c *Client) {
+ c.httpClient = httpClient
+ }
+}
+
+func WithRetryPolicyDisabled() ClientOption {
+ return func(c *Client) {
+ c.retryPolicyEnabled = false
+ }
+}
+
+// Client to be used to acquire tokens for managed identity.
+// ID: [SystemAssigned], [UserAssignedClientID], [UserAssignedResourceID], [UserAssignedObjectID]
+//
+// Options: [WithHTTPClient]
+func New(id ID, options ...ClientOption) (Client, error) {
+ source, err := GetSource()
+ if err != nil {
+ return Client{}, err
+ }
+
+ // Check for user-assigned restrictions based on the source
+ switch source {
+ case AzureArc:
+ switch id.(type) {
+ case UserAssignedClientID, UserAssignedResourceID, UserAssignedObjectID:
+ return Client{}, errors.New("Azure Arc doesn't support user-assigned managed identities")
+ }
+ case AzureML:
+ switch id.(type) {
+ case UserAssignedObjectID, UserAssignedResourceID:
+ return Client{}, errors.New("Azure ML supports specifying a user-assigned managed identity by client ID only")
+ }
+ case CloudShell:
+ switch id.(type) {
+ case UserAssignedClientID, UserAssignedResourceID, UserAssignedObjectID:
+ return Client{}, errors.New("Cloud Shell doesn't support user-assigned managed identities")
+ }
+ case ServiceFabric:
+ switch id.(type) {
+ case UserAssignedClientID, UserAssignedResourceID, UserAssignedObjectID:
+ return Client{}, errors.New("Service Fabric API doesn't support specifying a user-assigned identity. The identity is determined by cluster resource configuration. See https://aka.ms/servicefabricmi")
+ }
+ }
+
+ switch t := id.(type) {
+ case UserAssignedClientID:
+ if len(string(t)) == 0 {
+ return Client{}, fmt.Errorf("empty %T", t)
+ }
+ case UserAssignedResourceID:
+ if len(string(t)) == 0 {
+ return Client{}, fmt.Errorf("empty %T", t)
+ }
+ case UserAssignedObjectID:
+ if len(string(t)) == 0 {
+ return Client{}, fmt.Errorf("empty %T", t)
+ }
+ case systemAssignedValue:
+ default:
+ return Client{}, fmt.Errorf("unsupported type %T", id)
+ }
+ zero := atomic.Value{}
+ zero.Store(false)
+ client := Client{
+ miType: id,
+ httpClient: shared.DefaultClient,
+ retryPolicyEnabled: true,
+ source: source,
+ canRefresh: &zero,
+ }
+ for _, option := range options {
+ option(&client)
+ }
+ fakeAuthInfo, err := authority.NewInfoFromAuthorityURI("https://login.microsoftonline.com/managed_identity", false, true)
+ if err != nil {
+ return Client{}, err
+ }
+ client.authParams = authority.NewAuthParams(client.miType.value(), fakeAuthInfo)
+ return client, nil
+}
+
+// GetSource detects and returns the managed identity source available on the environment.
+func GetSource() (Source, error) {
+ identityEndpoint := os.Getenv(identityEndpointEnvVar)
+ identityHeader := os.Getenv(identityHeaderEnvVar)
+ identityServerThumbprint := os.Getenv(identityServerThumbprintEnvVar)
+ msiEndpoint := os.Getenv(msiEndpointEnvVar)
+ msiSecret := os.Getenv(msiSecretEnvVar)
+ imdsEndpoint := os.Getenv(imdsEndVar)
+
+ if identityEndpoint != "" && identityHeader != "" {
+ if identityServerThumbprint != "" {
+ return ServiceFabric, nil
+ }
+ return AppService, nil
+ } else if msiEndpoint != "" {
+ if msiSecret != "" {
+ return AzureML, nil
+ } else {
+ return CloudShell, nil
+ }
+ } else if isAzureArcEnvironment(identityEndpoint, imdsEndpoint) {
+ return AzureArc, nil
+ }
+
+ return DefaultToIMDS, nil
+}
+
+// This function wraps time.Now() and is used for refreshing the application
+// was created to test the function against refreshin
+var now = time.Now
+
+// Acquires tokens from the configured managed identity on an azure resource.
+//
+// Resource: scopes application is requesting access to
+// Options: [WithClaims]
+func (c Client) AcquireToken(ctx context.Context, resource string, options ...AcquireTokenOption) (AuthResult, error) {
+ resource = strings.TrimSuffix(resource, "/.default")
+ o := AcquireTokenOptions{}
+ for _, option := range options {
+ option(&o)
+ }
+ c.authParams.Scopes = []string{resource}
+
+ // ignore cached access tokens when given claims
+ if o.claims == "" {
+ stResp, err := cacheManager.Read(ctx, c.authParams)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ ar, err := base.AuthResultFromStorage(stResp)
+ if err == nil {
+ if !stResp.AccessToken.RefreshOn.T.IsZero() && !stResp.AccessToken.RefreshOn.T.After(now()) && c.canRefresh.CompareAndSwap(false, true) {
+ defer c.canRefresh.Store(false)
+ if tr, er := c.getToken(ctx, resource); er == nil {
+ return tr, nil
+ }
+ }
+ ar.AccessToken, err = c.authParams.AuthnScheme.FormatAccessToken(ar.AccessToken)
+ return ar, err
+ }
+ }
+ return c.getToken(ctx, resource)
+}
+
+func (c Client) getToken(ctx context.Context, resource string) (AuthResult, error) {
+ switch c.source {
+ case AzureArc:
+ return c.acquireTokenForAzureArc(ctx, resource)
+ case AzureML:
+ return c.acquireTokenForAzureML(ctx, resource)
+ case CloudShell:
+ return c.acquireTokenForCloudShell(ctx, resource)
+ case DefaultToIMDS:
+ return c.acquireTokenForIMDS(ctx, resource)
+ case AppService:
+ return c.acquireTokenForAppService(ctx, resource)
+ case ServiceFabric:
+ return c.acquireTokenForServiceFabric(ctx, resource)
+ default:
+ return AuthResult{}, fmt.Errorf("unsupported source %q", c.source)
+ }
+}
+
+func (c Client) acquireTokenForAppService(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createAppServiceAuthRequest(ctx, c.miType, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ tokenResponse, err := c.getTokenForRequest(req, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func (c Client) acquireTokenForIMDS(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createIMDSAuthRequest(ctx, c.miType, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ tokenResponse, err := c.getTokenForRequest(req, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func (c Client) acquireTokenForCloudShell(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createCloudShellAuthRequest(ctx, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ tokenResponse, err := c.getTokenForRequest(req, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func (c Client) acquireTokenForAzureML(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createAzureMLAuthRequest(ctx, c.miType, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ tokenResponse, err := c.getTokenForRequest(req, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func (c Client) acquireTokenForServiceFabric(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createServiceFabricAuthRequest(ctx, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ tokenResponse, err := c.getTokenForRequest(req, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func (c Client) acquireTokenForAzureArc(ctx context.Context, resource string) (AuthResult, error) {
+ req, err := createAzureArcAuthRequest(ctx, resource, "")
+ if err != nil {
+ return AuthResult{}, err
+ }
+
+ response, err := c.httpClient.Do(req)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ defer response.Body.Close()
+
+ if response.StatusCode != http.StatusUnauthorized {
+ return AuthResult{}, fmt.Errorf("expected a 401 response, received %d", response.StatusCode)
+ }
+
+ secret, err := c.getAzureArcSecretKey(response, runtime.GOOS)
+ if err != nil {
+ return AuthResult{}, err
+ }
+
+ secondRequest, err := createAzureArcAuthRequest(ctx, resource, string(secret))
+ if err != nil {
+ return AuthResult{}, err
+ }
+
+ tokenResponse, err := c.getTokenForRequest(secondRequest, resource)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return authResultFromToken(c.authParams, tokenResponse)
+}
+
+func authResultFromToken(authParams authority.AuthParams, token accesstokens.TokenResponse) (AuthResult, error) {
+ if cacheManager == nil {
+ return AuthResult{}, errors.New("cache instance is nil")
+ }
+ account, err := cacheManager.Write(authParams, token)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ // if refreshOn is not set, set it to half of the time until expiry if expiry is more than 2 hours away
+ if token.RefreshOn.T.IsZero() {
+ if lifetime := time.Until(token.ExpiresOn); lifetime > 2*time.Hour {
+ token.RefreshOn.T = time.Now().Add(lifetime / 2)
+ }
+ }
+ ar, err := base.NewAuthResult(token, account)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ ar.AccessToken, err = authParams.AuthnScheme.FormatAccessToken(ar.AccessToken)
+ return ar, err
+}
+
+// contains checks if the element is present in the list.
+func contains[T comparable](list []T, element T) bool {
+ for _, v := range list {
+ if v == element {
+ return true
+ }
+ }
+ return false
+}
+
+// retry performs an HTTP request with retries based on the provided options.
+func (c Client) retry(maxRetries int, req *http.Request) (*http.Response, error) {
+ var resp *http.Response
+ var err error
+ for attempt := 0; attempt < maxRetries; attempt++ {
+ tryCtx, tryCancel := context.WithTimeout(req.Context(), time.Minute)
+ defer tryCancel()
+ if resp != nil && resp.Body != nil {
+ _, _ = io.Copy(io.Discard, resp.Body)
+ resp.Body.Close()
+ }
+ cloneReq := req.Clone(tryCtx)
+ resp, err = c.httpClient.Do(cloneReq)
+ retrylist := retryStatusCodes
+ if c.source == DefaultToIMDS {
+ retrylist = retryCodesForIMDS
+ }
+ if err == nil && !contains(retrylist, resp.StatusCode) {
+ return resp, nil
+ }
+ select {
+ case <-time.After(time.Second):
+ case <-req.Context().Done():
+ err = req.Context().Err()
+ return resp, err
+ }
+ }
+ return resp, err
+}
+
+func (c Client) getTokenForRequest(req *http.Request, resource string) (accesstokens.TokenResponse, error) {
+ r := accesstokens.TokenResponse{}
+ var resp *http.Response
+ var err error
+
+ if c.retryPolicyEnabled {
+ resp, err = c.retry(defaultRetryCount, req)
+ } else {
+ resp, err = c.httpClient.Do(req)
+ }
+ if err != nil {
+ return r, err
+ }
+ responseBytes, err := io.ReadAll(resp.Body)
+ defer resp.Body.Close()
+ if err != nil {
+ return r, err
+ }
+ switch resp.StatusCode {
+ case http.StatusOK, http.StatusAccepted:
+ default:
+ sd := strings.TrimSpace(string(responseBytes))
+ if sd != "" {
+ return r, errors.CallErr{
+ Req: req,
+ Resp: resp,
+ Err: fmt.Errorf("http call(%s)(%s) error: reply status code was %d:\n%s",
+ req.URL.String(),
+ req.Method,
+ resp.StatusCode,
+ sd),
+ }
+ }
+ return r, errors.CallErr{
+ Req: req,
+ Resp: resp,
+ Err: fmt.Errorf("http call(%s)(%s) error: reply status code was %d", req.URL.String(), req.Method, resp.StatusCode),
+ }
+ }
+
+ err = json.Unmarshal(responseBytes, &r)
+ if err != nil {
+ return r, errors.InvalidJsonErr{
+ Err: fmt.Errorf("error parsing the json error: %s", err),
+ }
+ }
+ r.GrantedScopes.Slice = append(r.GrantedScopes.Slice, resource)
+
+ return r, err
+}
+
+func createAppServiceAuthRequest(ctx context.Context, id ID, resource string) (*http.Request, error) {
+ identityEndpoint := os.Getenv(identityEndpointEnvVar)
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, identityEndpoint, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("X-IDENTITY-HEADER", os.Getenv(identityHeaderEnvVar))
+ q := req.URL.Query()
+ q.Set("api-version", appServiceAPIVersion)
+ q.Set("resource", resource)
+ switch t := id.(type) {
+ case UserAssignedClientID:
+ q.Set(miQueryParameterClientId, string(t))
+ case UserAssignedResourceID:
+ q.Set(miQueryParameterResourceId, string(t))
+ case UserAssignedObjectID:
+ q.Set(miQueryParameterObjectId, string(t))
+ case systemAssignedValue:
+ default:
+ return nil, fmt.Errorf("unsupported type %T", id)
+ }
+ req.URL.RawQuery = q.Encode()
+ return req, nil
+}
+
+func createIMDSAuthRequest(ctx context.Context, id ID, resource string) (*http.Request, error) {
+ msiEndpoint, err := url.Parse(imdsDefaultEndpoint)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse %q: %s", imdsDefaultEndpoint, err)
+ }
+ msiParameters := msiEndpoint.Query()
+ msiParameters.Set(apiVersionQueryParameterName, imdsAPIVersion)
+ msiParameters.Set(resourceQueryParameterName, resource)
+
+ switch t := id.(type) {
+ case UserAssignedClientID:
+ msiParameters.Set(miQueryParameterClientId, string(t))
+ case UserAssignedResourceID:
+ msiParameters.Set(miQueryParameterResourceIdIMDS, string(t))
+ case UserAssignedObjectID:
+ msiParameters.Set(miQueryParameterObjectId, string(t))
+ case systemAssignedValue: // not adding anything
+ default:
+ return nil, fmt.Errorf("unsupported type %T", id)
+ }
+
+ msiEndpoint.RawQuery = msiParameters.Encode()
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, msiEndpoint.String(), nil)
+ if err != nil {
+ return nil, fmt.Errorf("error creating http request %s", err)
+ }
+ req.Header.Set(metaHTTPHeaderName, "true")
+ return req, nil
+}
+
+func createAzureArcAuthRequest(ctx context.Context, resource string, key string) (*http.Request, error) {
+ identityEndpoint := os.Getenv(identityEndpointEnvVar)
+ if identityEndpoint == "" {
+ identityEndpoint = azureArcEndpoint
+ }
+ msiEndpoint, parseErr := url.Parse(identityEndpoint)
+
+ if parseErr != nil {
+ return nil, fmt.Errorf("couldn't parse %q: %s", identityEndpoint, parseErr)
+ }
+
+ msiParameters := msiEndpoint.Query()
+ msiParameters.Set(apiVersionQueryParameterName, azureArcAPIVersion)
+ msiParameters.Set(resourceQueryParameterName, resource)
+
+ msiEndpoint.RawQuery = msiParameters.Encode()
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, msiEndpoint.String(), nil)
+ if err != nil {
+ return nil, fmt.Errorf("error creating http request %s", err)
+ }
+ req.Header.Set(metaHTTPHeaderName, "true")
+
+ if key != "" {
+ req.Header.Set("Authorization", fmt.Sprintf("Basic %s", key))
+ }
+
+ return req, nil
+}
+
+func isAzureArcEnvironment(identityEndpoint, imdsEndpoint string) bool {
+ if identityEndpoint != "" && imdsEndpoint != "" {
+ return true
+ }
+ himdsFilePath := getAzureArcHimdsFilePath(runtime.GOOS)
+ if himdsFilePath != "" {
+ if _, err := os.Stat(himdsFilePath); err == nil {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *Client) getAzureArcSecretKey(response *http.Response, platform string) (string, error) {
+ wwwAuthenticateHeader := response.Header.Get(wwwAuthenticateHeaderName)
+
+ if len(wwwAuthenticateHeader) == 0 {
+ return "", errors.New("response has no www-authenticate header")
+ }
+
+ // check if the platform is supported
+ expectedSecretFilePath := getAzureArcPlatformPath(platform)
+ if expectedSecretFilePath == "" {
+ return "", errors.New("platform not supported, expected linux or windows")
+ }
+
+ parts := strings.Split(wwwAuthenticateHeader, "Basic realm=")
+ if len(parts) < 2 {
+ return "", fmt.Errorf("basic realm= not found in the string, instead found: %s", wwwAuthenticateHeader)
+ }
+
+ secretFilePath := parts
+
+ // check that the file in the file path is a .key file
+ fileName := filepath.Base(secretFilePath[1])
+ if !strings.HasSuffix(fileName, azureArcFileExtension) {
+ return "", fmt.Errorf("invalid file extension, expected %s, got %s", azureArcFileExtension, filepath.Ext(fileName))
+ }
+
+ // check that file path from header matches the expected file path for the platform
+ if expectedSecretFilePath != filepath.Dir(secretFilePath[1]) {
+ return "", fmt.Errorf("invalid file path, expected %s, got %s", expectedSecretFilePath, filepath.Dir(secretFilePath[1]))
+ }
+
+ fileInfo, err := os.Stat(secretFilePath[1])
+ if err != nil {
+ return "", fmt.Errorf("failed to get metadata for %s due to error: %s", secretFilePath[1], err)
+ }
+
+ // Throw an error if the secret file's size is greater than 4096 bytes
+ if s := fileInfo.Size(); s > azureArcMaxFileSizeBytes {
+ return "", fmt.Errorf("invalid secret file size, expected %d, file size was %d", azureArcMaxFileSizeBytes, s)
+ }
+
+ // Attempt to read the contents of the secret file
+ secret, err := os.ReadFile(secretFilePath[1])
+ if err != nil {
+ return "", fmt.Errorf("failed to read %q due to error: %s", secretFilePath[1], err)
+ }
+
+ return string(secret), nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/servicefabric.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/servicefabric.go
new file mode 100644
index 000000000..535065e9d
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity/servicefabric.go
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+package managedidentity
+
+import (
+ "context"
+ "net/http"
+ "os"
+)
+
+func createServiceFabricAuthRequest(ctx context.Context, resource string) (*http.Request, error) {
+ identityEndpoint := os.Getenv(identityEndpointEnvVar)
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, identityEndpoint, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Accept", "application/json")
+ req.Header.Set("Secret", os.Getenv(identityHeaderEnvVar))
+ q := req.URL.Query()
+ q.Set("api-version", serviceFabricAPIVersion)
+ q.Set("resource", resource)
+ req.URL.RawQuery = q.Encode()
+ return req, nil
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
new file mode 100644
index 000000000..797c086cb
--- /dev/null
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
@@ -0,0 +1,763 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+/*
+Package public provides a client for authentication of "public" applications. A "public"
+application is defined as an app that runs on client devices (android, ios, windows, linux, ...).
+These devices are "untrusted" and access resources via web APIs that must authenticate.
+*/
+package public
+
+/*
+Design note:
+
+public.Client uses client.Base as an embedded type. client.Base statically assigns its attributes
+during creation. As it doesn't have any pointers in it, anything borrowed from it, such as
+Base.AuthParams is a copy that is free to be manipulated here.
+*/
+
+// TODO(msal): This should have example code for each method on client using Go's example doc framework.
+// base usage details should be includee in the package documentation.
+
+import (
+ "context"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "net/url"
+ "reflect"
+ "strconv"
+
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/options"
+ "github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared"
+ "github.com/google/uuid"
+ "github.com/pkg/browser"
+)
+
+// AuthResult contains the results of one token acquisition operation.
+// For details see https://aka.ms/msal-net-authenticationresult
+type AuthResult = base.AuthResult
+
+type AuthenticationScheme = authority.AuthenticationScheme
+
+type Account = shared.Account
+
+type TokenSource = base.TokenSource
+
+const (
+ TokenSourceIdentityProvider = base.TokenSourceIdentityProvider
+ TokenSourceCache = base.TokenSourceCache
+)
+
+var errNoAccount = errors.New("no account was specified with public.WithSilentAccount(), or the specified account is invalid")
+
+// clientOptions configures the Client's behavior.
+type clientOptions struct {
+ accessor cache.ExportReplace
+ authority string
+ capabilities []string
+ disableInstanceDiscovery bool
+ httpClient ops.HTTPClient
+}
+
+func (p *clientOptions) validate() error {
+ u, err := url.Parse(p.authority)
+ if err != nil {
+ return fmt.Errorf("Authority options cannot be URL parsed: %w", err)
+ }
+ if u.Scheme != "https" {
+ return fmt.Errorf("Authority(%s) did not start with https://", u.String())
+ }
+ return nil
+}
+
+// Option is an optional argument to the New constructor.
+type Option func(o *clientOptions)
+
+// WithAuthority allows for a custom authority to be set. This must be a valid https url.
+func WithAuthority(authority string) Option {
+ return func(o *clientOptions) {
+ o.authority = authority
+ }
+}
+
+// WithCache provides an accessor that will read and write authentication data to an externally managed cache.
+func WithCache(accessor cache.ExportReplace) Option {
+ return func(o *clientOptions) {
+ o.accessor = accessor
+ }
+}
+
+// WithClientCapabilities allows configuring one or more client capabilities such as "CP1"
+func WithClientCapabilities(capabilities []string) Option {
+ return func(o *clientOptions) {
+ // there's no danger of sharing the slice's underlying memory with the application because
+ // this slice is simply passed to base.WithClientCapabilities, which copies its data
+ o.capabilities = capabilities
+ }
+}
+
+// WithHTTPClient allows for a custom HTTP client to be set.
+func WithHTTPClient(httpClient ops.HTTPClient) Option {
+ return func(o *clientOptions) {
+ o.httpClient = httpClient
+ }
+}
+
+// WithInstanceDiscovery set to false to disable authority validation (to support private cloud scenarios)
+func WithInstanceDiscovery(enabled bool) Option {
+ return func(o *clientOptions) {
+ o.disableInstanceDiscovery = !enabled
+ }
+}
+
+// Client is a representation of authentication client for public applications as defined in the
+// package doc. For more information, visit https://docs.microsoft.com/azure/active-directory/develop/msal-client-applications.
+type Client struct {
+ base base.Client
+}
+
+// New is the constructor for Client.
+func New(clientID string, options ...Option) (Client, error) {
+ opts := clientOptions{
+ authority: base.AuthorityPublicCloud,
+ httpClient: shared.DefaultClient,
+ }
+
+ for _, o := range options {
+ o(&opts)
+ }
+ if err := opts.validate(); err != nil {
+ return Client{}, err
+ }
+
+ base, err := base.New(clientID, opts.authority, oauth.New(opts.httpClient), base.WithCacheAccessor(opts.accessor), base.WithClientCapabilities(opts.capabilities), base.WithInstanceDiscovery(!opts.disableInstanceDiscovery))
+ if err != nil {
+ return Client{}, err
+ }
+ return Client{base}, nil
+}
+
+// authCodeURLOptions contains options for AuthCodeURL
+type authCodeURLOptions struct {
+ claims, loginHint, tenantID, domainHint string
+}
+
+// AuthCodeURLOption is implemented by options for AuthCodeURL
+type AuthCodeURLOption interface {
+ authCodeURLOption()
+}
+
+// AuthCodeURL creates a URL used to acquire an authorization code.
+//
+// Options: [WithClaims], [WithDomainHint], [WithLoginHint], [WithTenantID]
+func (pca Client) AuthCodeURL(ctx context.Context, clientID, redirectURI string, scopes []string, opts ...AuthCodeURLOption) (string, error) {
+ o := authCodeURLOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return "", err
+ }
+ ap, err := pca.base.AuthParams.WithTenant(o.tenantID)
+ if err != nil {
+ return "", err
+ }
+ ap.Claims = o.claims
+ ap.LoginHint = o.loginHint
+ ap.DomainHint = o.domainHint
+ return pca.base.AuthCodeURL(ctx, clientID, redirectURI, scopes, ap)
+}
+
+// WithClaims sets additional claims to request for the token, such as those required by conditional access policies.
+// Use this option when Azure AD returned a claims challenge for a prior request. The argument must be decoded.
+// This option is valid for any token acquisition method.
+func WithClaims(claims string) interface {
+ AcquireByAuthCodeOption
+ AcquireByDeviceCodeOption
+ AcquireByUsernamePasswordOption
+ AcquireInteractiveOption
+ AcquireSilentOption
+ AuthCodeURLOption
+ options.CallOption
+} {
+ return struct {
+ AcquireByAuthCodeOption
+ AcquireByDeviceCodeOption
+ AcquireByUsernamePasswordOption
+ AcquireInteractiveOption
+ AcquireSilentOption
+ AuthCodeURLOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenByAuthCodeOptions:
+ t.claims = claims
+ case *acquireTokenByDeviceCodeOptions:
+ t.claims = claims
+ case *acquireTokenByUsernamePasswordOptions:
+ t.claims = claims
+ case *acquireTokenSilentOptions:
+ t.claims = claims
+ case *authCodeURLOptions:
+ t.claims = claims
+ case *interactiveAuthOptions:
+ t.claims = claims
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithAuthenticationScheme is an extensibility mechanism designed to be used only by Azure Arc for proof of possession access tokens.
+func WithAuthenticationScheme(authnScheme AuthenticationScheme) interface {
+ AcquireSilentOption
+ AcquireInteractiveOption
+ AcquireByUsernamePasswordOption
+ options.CallOption
+} {
+ return struct {
+ AcquireSilentOption
+ AcquireInteractiveOption
+ AcquireByUsernamePasswordOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenSilentOptions:
+ t.authnScheme = authnScheme
+ case *interactiveAuthOptions:
+ t.authnScheme = authnScheme
+ case *acquireTokenByUsernamePasswordOptions:
+ t.authnScheme = authnScheme
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithTenantID specifies a tenant for a single authentication. It may be different than the tenant set in [New] by [WithAuthority].
+// This option is valid for any token acquisition method.
+func WithTenantID(tenantID string) interface {
+ AcquireByAuthCodeOption
+ AcquireByDeviceCodeOption
+ AcquireByUsernamePasswordOption
+ AcquireInteractiveOption
+ AcquireSilentOption
+ AuthCodeURLOption
+ options.CallOption
+} {
+ return struct {
+ AcquireByAuthCodeOption
+ AcquireByDeviceCodeOption
+ AcquireByUsernamePasswordOption
+ AcquireInteractiveOption
+ AcquireSilentOption
+ AuthCodeURLOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenByAuthCodeOptions:
+ t.tenantID = tenantID
+ case *acquireTokenByDeviceCodeOptions:
+ t.tenantID = tenantID
+ case *acquireTokenByUsernamePasswordOptions:
+ t.tenantID = tenantID
+ case *acquireTokenSilentOptions:
+ t.tenantID = tenantID
+ case *authCodeURLOptions:
+ t.tenantID = tenantID
+ case *interactiveAuthOptions:
+ t.tenantID = tenantID
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// acquireTokenSilentOptions are all the optional settings to an AcquireTokenSilent() call.
+// These are set by using various AcquireTokenSilentOption functions.
+type acquireTokenSilentOptions struct {
+ account Account
+ claims, tenantID string
+ authnScheme AuthenticationScheme
+}
+
+// AcquireSilentOption is implemented by options for AcquireTokenSilent
+type AcquireSilentOption interface {
+ acquireSilentOption()
+}
+
+// WithSilentAccount uses the passed account during an AcquireTokenSilent() call.
+func WithSilentAccount(account Account) interface {
+ AcquireSilentOption
+ options.CallOption
+} {
+ return struct {
+ AcquireSilentOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenSilentOptions:
+ t.account = account
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// AcquireTokenSilent acquires a token from either the cache or using a refresh token.
+//
+// Options: [WithClaims], [WithSilentAccount], [WithTenantID]
+func (pca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts ...AcquireSilentOption) (AuthResult, error) {
+ o := acquireTokenSilentOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return AuthResult{}, err
+ }
+ // an account is required to find user tokens in the cache
+ if reflect.ValueOf(o.account).IsZero() {
+ return AuthResult{}, errNoAccount
+ }
+
+ silentParameters := base.AcquireTokenSilentParameters{
+ Scopes: scopes,
+ Account: o.account,
+ Claims: o.claims,
+ RequestType: accesstokens.ATPublic,
+ IsAppCache: false,
+ TenantID: o.tenantID,
+ AuthnScheme: o.authnScheme,
+ }
+
+ return pca.base.AcquireTokenSilent(ctx, silentParameters)
+}
+
+// acquireTokenByUsernamePasswordOptions contains optional configuration for AcquireTokenByUsernamePassword
+type acquireTokenByUsernamePasswordOptions struct {
+ claims, tenantID string
+ authnScheme AuthenticationScheme
+}
+
+// AcquireByUsernamePasswordOption is implemented by options for AcquireTokenByUsernamePassword
+type AcquireByUsernamePasswordOption interface {
+ acquireByUsernamePasswordOption()
+}
+
+// Deprecated: This API will be removed in a future release. Use a more secure flow instead. Follow this migration guide: https://aka.ms/msal-ropc-migration
+//
+// AcquireTokenByUsernamePassword acquires a security token from the authority, via Username/Password Authentication.
+// Options: [WithClaims], [WithTenantID]
+func (pca Client) AcquireTokenByUsernamePassword(ctx context.Context, scopes []string, username, password string, opts ...AcquireByUsernamePasswordOption) (AuthResult, error) {
+ o := acquireTokenByUsernamePasswordOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return AuthResult{}, err
+ }
+ authParams, err := pca.base.AuthParams.WithTenant(o.tenantID)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ authParams.Scopes = scopes
+ authParams.AuthorizationType = authority.ATUsernamePassword
+ authParams.Claims = o.claims
+ authParams.Username = username
+ authParams.Password = password
+ if o.authnScheme != nil {
+ authParams.AuthnScheme = o.authnScheme
+ }
+
+ token, err := pca.base.Token.UsernamePassword(ctx, authParams)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return pca.base.AuthResultFromToken(ctx, authParams, token)
+}
+
+type DeviceCodeResult = accesstokens.DeviceCodeResult
+
+// DeviceCode provides the results of the device code flows first stage (containing the code)
+// that must be entered on the second device and provides a method to retrieve the AuthenticationResult
+// once that code has been entered and verified.
+type DeviceCode struct {
+ // Result holds the information about the device code (such as the code).
+ Result DeviceCodeResult
+
+ authParams authority.AuthParams
+ client Client
+ dc oauth.DeviceCode
+}
+
+// AuthenticationResult retreives the AuthenticationResult once the user enters the code
+// on the second device. Until then it blocks until the .AcquireTokenByDeviceCode() context
+// is cancelled or the token expires.
+func (d DeviceCode) AuthenticationResult(ctx context.Context) (AuthResult, error) {
+ token, err := d.dc.Token(ctx)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ return d.client.base.AuthResultFromToken(ctx, d.authParams, token)
+}
+
+// acquireTokenByDeviceCodeOptions contains optional configuration for AcquireTokenByDeviceCode
+type acquireTokenByDeviceCodeOptions struct {
+ claims, tenantID string
+}
+
+// AcquireByDeviceCodeOption is implemented by options for AcquireTokenByDeviceCode
+type AcquireByDeviceCodeOption interface {
+ acquireByDeviceCodeOptions()
+}
+
+// AcquireTokenByDeviceCode acquires a security token from the authority, by acquiring a device code and using that to acquire the token.
+// Users need to create an AcquireTokenDeviceCodeParameters instance and pass it in.
+//
+// Options: [WithClaims], [WithTenantID]
+func (pca Client) AcquireTokenByDeviceCode(ctx context.Context, scopes []string, opts ...AcquireByDeviceCodeOption) (DeviceCode, error) {
+ o := acquireTokenByDeviceCodeOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return DeviceCode{}, err
+ }
+ authParams, err := pca.base.AuthParams.WithTenant(o.tenantID)
+ if err != nil {
+ return DeviceCode{}, err
+ }
+ authParams.Scopes = scopes
+ authParams.AuthorizationType = authority.ATDeviceCode
+ authParams.Claims = o.claims
+
+ dc, err := pca.base.Token.DeviceCode(ctx, authParams)
+ if err != nil {
+ return DeviceCode{}, err
+ }
+
+ return DeviceCode{Result: dc.Result, authParams: authParams, client: pca, dc: dc}, nil
+}
+
+// acquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow.
+type acquireTokenByAuthCodeOptions struct {
+ challenge, claims, tenantID string
+}
+
+// AcquireByAuthCodeOption is implemented by options for AcquireTokenByAuthCode
+type AcquireByAuthCodeOption interface {
+ acquireByAuthCodeOption()
+}
+
+// WithChallenge allows you to provide a code for the .AcquireTokenByAuthCode() call.
+func WithChallenge(challenge string) interface {
+ AcquireByAuthCodeOption
+ options.CallOption
+} {
+ return struct {
+ AcquireByAuthCodeOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenByAuthCodeOptions:
+ t.challenge = challenge
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// AcquireTokenByAuthCode is a request to acquire a security token from the authority, using an authorization code.
+// The specified redirect URI must be the same URI that was used when the authorization code was requested.
+//
+// Options: [WithChallenge], [WithClaims], [WithTenantID]
+func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, opts ...AcquireByAuthCodeOption) (AuthResult, error) {
+ o := acquireTokenByAuthCodeOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return AuthResult{}, err
+ }
+
+ params := base.AcquireTokenAuthCodeParameters{
+ Scopes: scopes,
+ Code: code,
+ Challenge: o.challenge,
+ Claims: o.claims,
+ AppType: accesstokens.ATPublic,
+ RedirectURI: redirectURI,
+ TenantID: o.tenantID,
+ }
+
+ return pca.base.AcquireTokenByAuthCode(ctx, params)
+}
+
+// Accounts gets all the accounts in the token cache.
+// If there are no accounts in the cache the returned slice is empty.
+func (pca Client) Accounts(ctx context.Context) ([]Account, error) {
+ return pca.base.AllAccounts(ctx)
+}
+
+// RemoveAccount signs the account out and forgets account from token cache.
+func (pca Client) RemoveAccount(ctx context.Context, account Account) error {
+ return pca.base.RemoveAccount(ctx, account)
+}
+
+// interactiveAuthOptions contains the optional parameters used to acquire an access token for interactive auth code flow.
+type interactiveAuthOptions struct {
+ claims, domainHint, loginHint, redirectURI, tenantID string
+ openURL func(url string) error
+ authnScheme AuthenticationScheme
+}
+
+// AcquireInteractiveOption is implemented by options for AcquireTokenInteractive
+type AcquireInteractiveOption interface {
+ acquireInteractiveOption()
+}
+
+// WithLoginHint pre-populates the login prompt with a username.
+func WithLoginHint(username string) interface {
+ AcquireInteractiveOption
+ AuthCodeURLOption
+ options.CallOption
+} {
+ return struct {
+ AcquireInteractiveOption
+ AuthCodeURLOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *authCodeURLOptions:
+ t.loginHint = username
+ case *interactiveAuthOptions:
+ t.loginHint = username
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithDomainHint adds the IdP domain as domain_hint query parameter in the auth url.
+func WithDomainHint(domain string) interface {
+ AcquireInteractiveOption
+ AuthCodeURLOption
+ options.CallOption
+} {
+ return struct {
+ AcquireInteractiveOption
+ AuthCodeURLOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *authCodeURLOptions:
+ t.domainHint = domain
+ case *interactiveAuthOptions:
+ t.domainHint = domain
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithRedirectURI sets a port for the local server used in interactive authentication, for
+// example http://localhost:port. All URI components other than the port are ignored.
+func WithRedirectURI(redirectURI string) interface {
+ AcquireInteractiveOption
+ options.CallOption
+} {
+ return struct {
+ AcquireInteractiveOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *interactiveAuthOptions:
+ t.redirectURI = redirectURI
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithOpenURL allows you to provide a function to open the browser to complete the interactive login, instead of launching the system default browser.
+func WithOpenURL(openURL func(url string) error) interface {
+ AcquireInteractiveOption
+ options.CallOption
+} {
+ return struct {
+ AcquireInteractiveOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *interactiveAuthOptions:
+ t.openURL = openURL
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// AcquireTokenInteractive acquires a security token from the authority using the default web browser to select the account.
+// https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows#interactive-and-non-interactive-authentication
+//
+// Options: [WithDomainHint], [WithLoginHint], [WithOpenURL], [WithRedirectURI], [WithTenantID]
+func (pca Client) AcquireTokenInteractive(ctx context.Context, scopes []string, opts ...AcquireInteractiveOption) (AuthResult, error) {
+ o := interactiveAuthOptions{}
+ if err := options.ApplyOptions(&o, opts); err != nil {
+ return AuthResult{}, err
+ }
+ // the code verifier is a random 32-byte sequence that's been base-64 encoded without padding.
+ // it's used to prevent MitM attacks during auth code flow, see https://tools.ietf.org/html/rfc7636
+ cv, challenge, err := codeVerifier()
+ if err != nil {
+ return AuthResult{}, err
+ }
+ var redirectURL *url.URL
+ if o.redirectURI != "" {
+ redirectURL, err = url.Parse(o.redirectURI)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ }
+ if o.openURL == nil {
+ o.openURL = browser.OpenURL
+ }
+ authParams, err := pca.base.AuthParams.WithTenant(o.tenantID)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ authParams.Scopes = scopes
+ authParams.AuthorizationType = authority.ATInteractive
+ authParams.Claims = o.claims
+ authParams.CodeChallenge = challenge
+ authParams.CodeChallengeMethod = "S256"
+ authParams.LoginHint = o.loginHint
+ authParams.DomainHint = o.domainHint
+ authParams.State = uuid.New().String()
+ authParams.Prompt = "select_account"
+ if o.authnScheme != nil {
+ authParams.AuthnScheme = o.authnScheme
+ }
+ res, err := pca.browserLogin(ctx, redirectURL, authParams, o.openURL)
+ if err != nil {
+ return AuthResult{}, err
+ }
+ authParams.Redirecturi = res.redirectURI
+
+ req, err := accesstokens.NewCodeChallengeRequest(authParams, accesstokens.ATPublic, nil, res.authCode, cv)
+ if err != nil {
+ return AuthResult{}, err
+ }
+
+ token, err := pca.base.Token.AuthCode(ctx, req)
+ if err != nil {
+ return AuthResult{}, err
+ }
+
+ return pca.base.AuthResultFromToken(ctx, authParams, token)
+}
+
+type interactiveAuthResult struct {
+ authCode string
+ redirectURI string
+}
+
+// parses the port number from the provided URL.
+// returns 0 if nil or no port is specified.
+func parsePort(u *url.URL) (int, error) {
+ if u == nil {
+ return 0, nil
+ }
+ p := u.Port()
+ if p == "" {
+ return 0, nil
+ }
+ return strconv.Atoi(p)
+}
+
+// browserLogin calls openURL and waits for a user to log in
+func (pca Client) browserLogin(ctx context.Context, redirectURI *url.URL, params authority.AuthParams, openURL func(string) error) (interactiveAuthResult, error) {
+ // start local redirect server so login can call us back
+ port, err := parsePort(redirectURI)
+ if err != nil {
+ return interactiveAuthResult{}, err
+ }
+ srv, err := local.New(params.State, port)
+ if err != nil {
+ return interactiveAuthResult{}, err
+ }
+ defer srv.Shutdown()
+ params.Scopes = accesstokens.AppendDefaultScopes(params)
+ authURL, err := pca.base.AuthCodeURL(ctx, params.ClientID, srv.Addr, params.Scopes, params)
+ if err != nil {
+ return interactiveAuthResult{}, err
+ }
+ // open browser window so user can select credentials
+ if err := openURL(authURL); err != nil {
+ return interactiveAuthResult{}, err
+ }
+ // now wait until the logic calls us back
+ res := srv.Result(ctx)
+ if res.Err != nil {
+ return interactiveAuthResult{}, res.Err
+ }
+ return interactiveAuthResult{
+ authCode: res.Code,
+ redirectURI: srv.Addr,
+ }, nil
+}
+
+// creates a code verifier string along with its SHA256 hash which
+// is used as the challenge when requesting an auth code.
+// used in interactive auth flow for PKCE.
+func codeVerifier() (codeVerifier string, challenge string, err error) {
+ cvBytes := make([]byte, 32)
+ if _, err = rand.Read(cvBytes); err != nil {
+ return
+ }
+ codeVerifier = base64.RawURLEncoding.EncodeToString(cvBytes)
+ // for PKCE, create a hash of the code verifier
+ cvh := sha256.Sum256([]byte(codeVerifier))
+ challenge = base64.RawURLEncoding.EncodeToString(cvh[:])
+ return
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/.gitignore b/vendor/github.com/golang-jwt/jwt/v5/.gitignore
new file mode 100644
index 000000000..09573e016
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+bin
+.idea/
+
diff --git a/vendor/github.com/golang-jwt/jwt/v5/LICENSE b/vendor/github.com/golang-jwt/jwt/v5/LICENSE
new file mode 100644
index 000000000..35dbc2520
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/LICENSE
@@ -0,0 +1,9 @@
+Copyright (c) 2012 Dave Grijalva
+Copyright (c) 2021 golang-jwt maintainers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md
new file mode 100644
index 000000000..b3178e751
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md
@@ -0,0 +1,195 @@
+# Migration Guide (v5.0.0)
+
+Version `v5` contains a major rework of core functionalities in the `jwt-go`
+library. This includes support for several validation options as well as a
+re-design of the `Claims` interface. Lastly, we reworked how errors work under
+the hood, which should provide a better overall developer experience.
+
+Starting from [v5.0.0](https://github.com/golang-jwt/jwt/releases/tag/v5.0.0),
+the import path will be:
+
+ "github.com/golang-jwt/jwt/v5"
+
+For most users, changing the import path *should* suffice. However, since we
+intentionally changed and cleaned some of the public API, existing programs
+might need to be updated. The following sections describe significant changes
+and corresponding updates for existing programs.
+
+## Parsing and Validation Options
+
+Under the hood, a new `Validator` struct takes care of validating the claims. A
+long awaited feature has been the option to fine-tune the validation of tokens.
+This is now possible with several `ParserOption` functions that can be appended
+to most `Parse` functions, such as `ParseWithClaims`. The most important options
+and changes are:
+ * Added `WithLeeway` to support specifying the leeway that is allowed when
+ validating time-based claims, such as `exp` or `nbf`.
+ * Changed default behavior to not check the `iat` claim. Usage of this claim
+ is OPTIONAL according to the JWT RFC. The claim itself is also purely
+ informational according to the RFC, so a strict validation failure is not
+ recommended. If you want to check for sensible values in these claims,
+ please use the `WithIssuedAt` parser option.
+ * Added `WithAudience`, `WithSubject` and `WithIssuer` to support checking for
+ expected `aud`, `sub` and `iss`.
+ * Added `WithStrictDecoding` and `WithPaddingAllowed` options to allow
+ previously global settings to enable base64 strict encoding and the parsing
+ of base64 strings with padding. The latter is strictly speaking against the
+ standard, but unfortunately some of the major identity providers issue some
+ of these incorrect tokens. Both options are disabled by default.
+
+## Changes to the `Claims` interface
+
+### Complete Restructuring
+
+Previously, the claims interface was satisfied with an implementation of a
+`Valid() error` function. This had several issues:
+ * The different claim types (struct claims, map claims, etc.) then contained
+ similar (but not 100 % identical) code of how this validation was done. This
+ lead to a lot of (almost) duplicate code and was hard to maintain
+ * It was not really semantically close to what a "claim" (or a set of claims)
+ really is; which is a list of defined key/value pairs with a certain
+ semantic meaning.
+
+Since all the validation functionality is now extracted into the validator, all
+`VerifyXXX` and `Valid` functions have been removed from the `Claims` interface.
+Instead, the interface now represents a list of getters to retrieve values with
+a specific meaning. This allows us to completely decouple the validation logic
+with the underlying storage representation of the claim, which could be a
+struct, a map or even something stored in a database.
+
+```go
+type Claims interface {
+ GetExpirationTime() (*NumericDate, error)
+ GetIssuedAt() (*NumericDate, error)
+ GetNotBefore() (*NumericDate, error)
+ GetIssuer() (string, error)
+ GetSubject() (string, error)
+ GetAudience() (ClaimStrings, error)
+}
+```
+
+Users that previously directly called the `Valid` function on their claims,
+e.g., to perform validation independently of parsing/verifying a token, can now
+use the `jwt.NewValidator` function to create a `Validator` independently of the
+`Parser`.
+
+```go
+var v = jwt.NewValidator(jwt.WithLeeway(5*time.Second))
+v.Validate(myClaims)
+```
+
+### Supported Claim Types and Removal of `StandardClaims`
+
+The two standard claim types supported by this library, `MapClaims` and
+`RegisteredClaims` both implement the necessary functions of this interface. The
+old `StandardClaims` struct, which has already been deprecated in `v4` is now
+removed.
+
+Users using custom claims, in most cases, will not experience any changes in the
+behavior as long as they embedded `RegisteredClaims`. If they created a new
+claim type from scratch, they now need to implemented the proper getter
+functions.
+
+### Migrating Application Specific Logic of the old `Valid`
+
+Previously, users could override the `Valid` method in a custom claim, for
+example to extend the validation with application-specific claims. However, this
+was always very dangerous, since once could easily disable the standard
+validation and signature checking.
+
+In order to avoid that, while still supporting the use-case, a new
+`ClaimsValidator` interface has been introduced. This interface consists of the
+`Validate() error` function. If the validator sees, that a `Claims` struct
+implements this interface, the errors returned to the `Validate` function will
+be *appended* to the regular standard validation. It is not possible to disable
+the standard validation anymore (even only by accident).
+
+Usage examples can be found in [example_test.go](./example_test.go), to build
+claims structs like the following.
+
+```go
+// MyCustomClaims includes all registered claims, plus Foo.
+type MyCustomClaims struct {
+ Foo string `json:"foo"`
+ jwt.RegisteredClaims
+}
+
+// Validate can be used to execute additional application-specific claims
+// validation.
+func (m MyCustomClaims) Validate() error {
+ if m.Foo != "bar" {
+ return errors.New("must be foobar")
+ }
+
+ return nil
+}
+```
+
+## Changes to the `Token` and `Parser` struct
+
+The previously global functions `DecodeSegment` and `EncodeSegment` were moved
+to the `Parser` and `Token` struct respectively. This will allow us in the
+future to configure the behavior of these two based on options supplied on the
+parser or the token (creation). This also removes two previously global
+variables and moves them to parser options `WithStrictDecoding` and
+`WithPaddingAllowed`.
+
+In order to do that, we had to adjust the way signing methods work. Previously
+they were given a base64 encoded signature in `Verify` and were expected to
+return a base64 encoded version of the signature in `Sign`, both as a `string`.
+However, this made it necessary to have `DecodeSegment` and `EncodeSegment`
+global and was a less than perfect design because we were repeating
+encoding/decoding steps for all signing methods. Now, `Sign` and `Verify`
+operate on a decoded signature as a `[]byte`, which feels more natural for a
+cryptographic operation anyway. Lastly, `Parse` and `SignedString` take care of
+the final encoding/decoding part.
+
+In addition to that, we also changed the `Signature` field on `Token` from a
+`string` to `[]byte` and this is also now populated with the decoded form. This
+is also more consistent, because the other parts of the JWT, mainly `Header` and
+`Claims` were already stored in decoded form in `Token`. Only the signature was
+stored in base64 encoded form, which was redundant with the information in the
+`Raw` field, which contains the complete token as base64.
+
+```go
+type Token struct {
+ Raw string // Raw contains the raw token
+ Method SigningMethod // Method is the signing method used or to be used
+ Header map[string]any // Header is the first segment of the token in decoded form
+ Claims Claims // Claims is the second segment of the token in decoded form
+ Signature []byte // Signature is the third segment of the token in decoded form
+ Valid bool // Valid specifies if the token is valid
+}
+```
+
+Most (if not all) of these changes should not impact the normal usage of this
+library. Only users directly accessing the `Signature` field as well as
+developers of custom signing methods should be affected.
+
+# Migration Guide (v4.0.0)
+
+Starting from [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0),
+the import path will be:
+
+ "github.com/golang-jwt/jwt/v4"
+
+The `/v4` version will be backwards compatible with existing `v3.x.y` tags in
+this repo, as well as `github.com/dgrijalva/jwt-go`. For most users this should
+be a drop-in replacement, if you're having troubles migrating, please open an
+issue.
+
+You can replace all occurrences of `github.com/dgrijalva/jwt-go` or
+`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually
+or by using tools such as `sed` or `gofmt`.
+
+And then you'd typically run:
+
+```
+go get github.com/golang-jwt/jwt/v4
+go mod tidy
+```
+
+# Older releases (before v3.2.0)
+
+The original migration guide for older releases can be found at
+https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md.
diff --git a/vendor/github.com/golang-jwt/jwt/v5/README.md b/vendor/github.com/golang-jwt/jwt/v5/README.md
new file mode 100644
index 000000000..0bb636f22
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/README.md
@@ -0,0 +1,167 @@
+# jwt-go
+
+[](https://github.com/golang-jwt/jwt/actions/workflows/build.yml)
+[](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
+[](https://coveralls.io/github/golang-jwt/jwt?branch=main)
+
+A [go](http://www.golang.org) (or 'golang' for search engine friendliness)
+implementation of [JSON Web
+Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
+
+Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0)
+this project adds Go module support, but maintains backward compatibility with
+older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the
+[`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version
+v5.0.0 introduces major improvements to the validation of tokens, but is not
+entirely backward compatible.
+
+> After the original author of the library suggested migrating the maintenance
+> of `jwt-go`, a dedicated team of open source maintainers decided to clone the
+> existing library into this repository. See
+> [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a
+> detailed discussion on this topic.
+
+
+**SECURITY NOTICE:** Some older versions of Go have a security issue in the
+crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
+[dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more
+detail.
+
+**SECURITY NOTICE:** It's important that you [validate the `alg` presented is
+what you
+expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/).
+This library attempts to make it easy to do the right thing by requiring key
+types to match the expected alg, but you should take the extra step to verify it in
+your usage. See the examples provided.
+
+### Supported Go versions
+
+Our support of Go versions is aligned with Go's [version release
+policy](https://golang.org/doc/devel/release#policy). So we will support a major
+version of Go until there are two newer major releases. We no longer support
+building jwt-go with unsupported Go versions, as these contain security
+vulnerabilities that will not be fixed.
+
+## What the heck is a JWT?
+
+JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web
+Tokens.
+
+In short, it's a signed JSON object that does something useful (for example,
+authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is
+made of three parts, separated by `.`'s. The first two parts are JSON objects,
+that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648)
+encoded. The last part is the signature, encoded the same way.
+
+The first part is called the header. It contains the necessary information for
+verifying the last part, the signature. For example, which encryption method
+was used for signing and what key was used.
+
+The part in the middle is the interesting bit. It's called the Claims and
+contains the actual stuff you care about. Refer to [RFC
+7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about
+reserved keys and the proper way to add your own.
+
+## What's in the box?
+
+This library supports the parsing and verification as well as the generation and
+signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA,
+RSA-PSS, and ECDSA, though hooks are present for adding your own.
+
+## Installation Guidelines
+
+1. To install the jwt package, you first need to have
+ [Go](https://go.dev/doc/install) installed, then you can use the command
+ below to add `jwt-go` as a dependency in your Go program.
+
+```sh
+go get -u github.com/golang-jwt/jwt/v5
+```
+
+2. Import it in your code:
+
+```go
+import "github.com/golang-jwt/jwt/v5"
+```
+
+## Usage
+
+A detailed usage guide, including how to sign and verify tokens can be found on
+our [documentation website](https://golang-jwt.github.io/jwt/usage/create/).
+
+## Examples
+
+See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
+for examples of usage:
+
+* [Simple example of parsing and validating a
+ token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-Parse-Hmac)
+* [Simple example of building and signing a
+ token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-New-Hmac)
+* [Directory of
+ Examples](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#pkg-examples)
+
+## Compliance
+
+This library was last reviewed to comply with [RFC
+7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few
+notable differences:
+
+* In order to protect against accidental use of [Unsecured
+ JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using
+ `alg=none` will only be accepted if the constant
+ `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
+
+## Project Status & Versioning
+
+This library is considered production ready. Feedback and feature requests are
+appreciated. The API should be considered stable. There should be very few
+backward-incompatible changes outside of major version updates (and only with
+good reason).
+
+This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull
+requests will land on `main`. Periodically, versions will be tagged from
+`main`. You can find all the releases on [the project releases
+page](https://github.com/golang-jwt/jwt/releases).
+
+**BREAKING CHANGES:** A full list of breaking changes is available in
+`VERSION_HISTORY.md`. See [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information on updating
+your code.
+
+## Extensions
+
+This library publishes all the necessary components for adding your own signing
+methods or key functions. Simply implement the `SigningMethod` interface and
+register a factory method using `RegisterSigningMethod` or provide a
+`jwt.Keyfunc`.
+
+A common use case would be integrating with different 3rd party signature
+providers, like key management services from various cloud providers or Hardware
+Security Modules (HSMs) or to implement additional standards.
+
+| Extension | Purpose | Repo |
+| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
+| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
+| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
+| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
+
+*Disclaimer*: Unless otherwise specified, these integrations are maintained by
+third parties and should not be considered as a primary offer by any of the
+mentioned cloud providers
+
+## More
+
+Go package documentation can be found [on
+pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt/v5). Additional
+documentation can be found on [our project
+page](https://golang-jwt.github.io/jwt/).
+
+The command line utility included in this project (cmd/jwt) provides a
+straightforward example of token creation and parsing as well as a useful tool
+for debugging your own integration. You'll also find several implementation
+examples in the documentation.
+
+[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version
+of the JWT logo, which is distributed under the terms of the [MIT
+License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt).
diff --git a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
new file mode 100644
index 000000000..2740597f1
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+## Supported Versions
+
+As of November 2024 (and until this document is updated), the latest version `v5` is supported. In critical cases, we might supply back-ported patches for `v4`.
+
+## Reporting a Vulnerability
+
+If you think you found a vulnerability, and even if you are not sure, please report it a [GitHub Security Advisory](https://github.com/golang-jwt/jwt/security/advisories/new). Please try be explicit, describe steps to reproduce the security issue with code example(s).
+
+You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem.
+
+## Public Discussions
+
+Please avoid publicly discussing a potential security vulnerability.
+
+Let's take this offline and find a solution first, this limits the potential impact as much as possible.
+
+We appreciate your help!
diff --git a/vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md b/vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md
new file mode 100644
index 000000000..b5039e49c
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md
@@ -0,0 +1,137 @@
+# `jwt-go` Version History
+
+The following version history is kept for historic purposes. To retrieve the current changes of each version, please refer to the change-log of the specific release versions on https://github.com/golang-jwt/jwt/releases.
+
+## 4.0.0
+
+* Introduces support for Go modules. The `v4` version will be backwards compatible with `v3.x.y`.
+
+## 3.2.2
+
+* Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)).
+* Fixed a potential issue that could occur when the verification of `exp`, `iat` or `nbf` was not required and contained invalid contents, i.e. non-numeric/date. Thanks for @thaJeztah for making us aware of that and @giorgos-f3 for originally reporting it to the formtech fork ([#40](https://github.com/golang-jwt/jwt/pull/40)).
+* Added support for EdDSA / ED25519 ([#36](https://github.com/golang-jwt/jwt/pull/36)).
+* Optimized allocations ([#33](https://github.com/golang-jwt/jwt/pull/33)).
+
+## 3.2.1
+
+* **Import Path Change**: See MIGRATION_GUIDE.md for tips on updating your code
+ * Changed the import path from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`
+* Fixed type confusing issue between `string` and `[]string` in `VerifyAudience` ([#12](https://github.com/golang-jwt/jwt/pull/12)). This fixes CVE-2020-26160
+
+#### 3.2.0
+
+* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
+* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
+* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
+* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
+
+#### 3.1.0
+
+* Improvements to `jwt` command line tool
+* Added `SkipClaimsValidation` option to `Parser`
+* Documentation updates
+
+#### 3.0.0
+
+* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
+ * Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
+ * `ParseFromRequest` has been moved to `request` subpackage and usage has changed
+ * The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims.
+* Other Additions and Changes
+ * Added `Claims` interface type to allow users to decode the claims into a custom type
+ * Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into.
+ * Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
+ * Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
+ * Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
+ * Added several new, more specific, validation errors to error type bitmask
+ * Moved examples from README to executable example files
+ * Signing method registry is now thread safe
+ * Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
+
+#### 2.7.0
+
+This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
+
+* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
+* Error text for expired tokens includes how long it's been expired
+* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
+* Documentation updates
+
+#### 2.6.0
+
+* Exposed inner error within ValidationError
+* Fixed validation errors when using UseJSONNumber flag
+* Added several unit tests
+
+#### 2.5.0
+
+* Added support for signing method none. You shouldn't use this. The API tries to make this clear.
+* Updated/fixed some documentation
+* Added more helpful error message when trying to parse tokens that begin with `BEARER `
+
+#### 2.4.0
+
+* Added new type, Parser, to allow for configuration of various parsing parameters
+ * You can now specify a list of valid signing methods. Anything outside this set will be rejected.
+ * You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
+* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
+* Fixed some bugs with ECDSA parsing
+
+#### 2.3.0
+
+* Added support for ECDSA signing methods
+* Added support for RSA PSS signing methods (requires go v1.4)
+
+#### 2.2.0
+
+* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic.
+
+#### 2.1.0
+
+Backwards compatible API change that was missed in 2.0.0.
+
+* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
+
+#### 2.0.0
+
+There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
+
+The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
+
+It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
+
+* **Compatibility Breaking Changes**
+ * `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
+ * `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
+ * `KeyFunc` now returns `interface{}` instead of `[]byte`
+ * `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
+ * `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
+* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type.
+ * Added public package global `SigningMethodHS256`
+ * Added public package global `SigningMethodHS384`
+ * Added public package global `SigningMethodHS512`
+* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type.
+ * Added public package global `SigningMethodRS256`
+ * Added public package global `SigningMethodRS384`
+ * Added public package global `SigningMethodRS512`
+* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged.
+* Refactored the RSA implementation to be easier to read
+* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
+
+## 1.0.2
+
+* Fixed bug in parsing public keys from certificates
+* Added more tests around the parsing of keys for RS256
+* Code refactoring in RS256 implementation. No functional changes
+
+## 1.0.1
+
+* Fixed panic if RS256 signing method was passed an invalid key
+
+## 1.0.0
+
+* First versioned release
+* API stabilized
+* Supports creating, signing, parsing, and validating JWT tokens
+* Supports RS256 and HS256 signing methods
diff --git a/vendor/github.com/golang-jwt/jwt/v5/claims.go b/vendor/github.com/golang-jwt/jwt/v5/claims.go
new file mode 100644
index 000000000..d50ff3dad
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/claims.go
@@ -0,0 +1,16 @@
+package jwt
+
+// Claims represent any form of a JWT Claims Set according to
+// https://datatracker.ietf.org/doc/html/rfc7519#section-4. In order to have a
+// common basis for validation, it is required that an implementation is able to
+// supply at least the claim names provided in
+// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely `exp`,
+// `iat`, `nbf`, `iss`, `sub` and `aud`.
+type Claims interface {
+ GetExpirationTime() (*NumericDate, error)
+ GetIssuedAt() (*NumericDate, error)
+ GetNotBefore() (*NumericDate, error)
+ GetIssuer() (string, error)
+ GetSubject() (string, error)
+ GetAudience() (ClaimStrings, error)
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/doc.go b/vendor/github.com/golang-jwt/jwt/v5/doc.go
new file mode 100644
index 000000000..a86dc1a3b
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/doc.go
@@ -0,0 +1,4 @@
+// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
+//
+// See README.md for more info.
+package jwt
diff --git a/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go
new file mode 100644
index 000000000..06cd94d23
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go
@@ -0,0 +1,134 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rand"
+ "errors"
+ "math/big"
+)
+
+var (
+ // Sadly this is missing from crypto/ecdsa compared to crypto/rsa
+ ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
+)
+
+// SigningMethodECDSA implements the ECDSA family of signing methods.
+// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
+type SigningMethodECDSA struct {
+ Name string
+ Hash crypto.Hash
+ KeySize int
+ CurveBits int
+}
+
+// Specific instances for EC256 and company
+var (
+ SigningMethodES256 *SigningMethodECDSA
+ SigningMethodES384 *SigningMethodECDSA
+ SigningMethodES512 *SigningMethodECDSA
+)
+
+func init() {
+ // ES256
+ SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
+ RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
+ return SigningMethodES256
+ })
+
+ // ES384
+ SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
+ RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
+ return SigningMethodES384
+ })
+
+ // ES512
+ SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
+ RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
+ return SigningMethodES512
+ })
+}
+
+func (m *SigningMethodECDSA) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an ecdsa.PublicKey struct
+func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key any) error {
+ // Get the key
+ var ecdsaKey *ecdsa.PublicKey
+ switch k := key.(type) {
+ case *ecdsa.PublicKey:
+ ecdsaKey = k
+ default:
+ return newError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType)
+ }
+
+ if len(sig) != 2*m.KeySize {
+ return ErrECDSAVerification
+ }
+
+ r := big.NewInt(0).SetBytes(sig[:m.KeySize])
+ s := big.NewInt(0).SetBytes(sig[m.KeySize:])
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Verify the signature
+ if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
+ return nil
+ }
+
+ return ErrECDSAVerification
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an ecdsa.PrivateKey struct
+func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]byte, error) {
+ // Get the key
+ var ecdsaKey *ecdsa.PrivateKey
+ switch k := key.(type) {
+ case *ecdsa.PrivateKey:
+ ecdsaKey = k
+ default:
+ return nil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType)
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return nil, ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return r, s
+ if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
+ curveBits := ecdsaKey.Curve.Params().BitSize
+
+ if m.CurveBits != curveBits {
+ return nil, ErrInvalidKey
+ }
+
+ keyBytes := curveBits / 8
+ if curveBits%8 > 0 {
+ keyBytes += 1
+ }
+
+ // We serialize the outputs (r and s) into big-endian byte arrays
+ // padded with zeros on the left to make sure the sizes work out.
+ // Output must be 2*keyBytes long.
+ out := make([]byte, 2*keyBytes)
+ r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
+ s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output.
+
+ return out, nil
+ } else {
+ return nil, err
+ }
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go b/vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go
new file mode 100644
index 000000000..44a3b7a1c
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go
@@ -0,0 +1,69 @@
+package jwt
+
+import (
+ "crypto/ecdsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrNotECPublicKey = errors.New("key is not a valid ECDSA public key")
+ ErrNotECPrivateKey = errors.New("key is not a valid ECDSA private key")
+)
+
+// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure
+func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey any
+ if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *ecdsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
+ return nil, ErrNotECPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseECPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
+func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey any
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+ parsedKey = cert.PublicKey
+ } else {
+ return nil, err
+ }
+ }
+
+ var pkey *ecdsa.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
+ return nil, ErrNotECPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/ed25519.go b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go
new file mode 100644
index 000000000..4159e57bf
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go
@@ -0,0 +1,79 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ed25519"
+ "crypto/rand"
+ "errors"
+)
+
+var (
+ ErrEd25519Verification = errors.New("ed25519: verification error")
+)
+
+// SigningMethodEd25519 implements the EdDSA family.
+// Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
+type SigningMethodEd25519 struct{}
+
+// Specific instance for EdDSA
+var (
+ SigningMethodEdDSA *SigningMethodEd25519
+)
+
+func init() {
+ SigningMethodEdDSA = &SigningMethodEd25519{}
+ RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() SigningMethod {
+ return SigningMethodEdDSA
+ })
+}
+
+func (m *SigningMethodEd25519) Alg() string {
+ return "EdDSA"
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an ed25519.PublicKey
+func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key any) error {
+ var ed25519Key ed25519.PublicKey
+ var ok bool
+
+ if ed25519Key, ok = key.(ed25519.PublicKey); !ok {
+ return newError("Ed25519 verify expects ed25519.PublicKey", ErrInvalidKeyType)
+ }
+
+ if len(ed25519Key) != ed25519.PublicKeySize {
+ return ErrInvalidKey
+ }
+
+ // Verify the signature
+ if !ed25519.Verify(ed25519Key, []byte(signingString), sig) {
+ return ErrEd25519Verification
+ }
+
+ return nil
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an ed25519.PrivateKey
+func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]byte, error) {
+ var ed25519Key crypto.Signer
+ var ok bool
+
+ if ed25519Key, ok = key.(crypto.Signer); !ok {
+ return nil, newError("Ed25519 sign expects crypto.Signer", ErrInvalidKeyType)
+ }
+
+ if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {
+ return nil, ErrInvalidKey
+ }
+
+ // Sign the string and return the result. ed25519 performs a two-pass hash
+ // as part of its algorithm. Therefore, we need to pass a non-prehashed
+ // message into the Sign function, as indicated by crypto.Hash(0)
+ sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0))
+ if err != nil {
+ return nil, err
+ }
+
+ return sig, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go b/vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go
new file mode 100644
index 000000000..6f46e8860
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go
@@ -0,0 +1,64 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ed25519"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key")
+ ErrNotEdPublicKey = errors.New("key is not a valid Ed25519 public key")
+)
+
+// ParseEdPrivateKeyFromPEM parses a PEM-encoded Edwards curve private key
+func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey any
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+
+ var pkey ed25519.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(ed25519.PrivateKey); !ok {
+ return nil, ErrNotEdPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseEdPublicKeyFromPEM parses a PEM-encoded Edwards curve public key
+func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey any
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ return nil, err
+ }
+
+ var pkey ed25519.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(ed25519.PublicKey); !ok {
+ return nil, ErrNotEdPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/errors.go b/vendor/github.com/golang-jwt/jwt/v5/errors.go
new file mode 100644
index 000000000..14e007516
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/errors.go
@@ -0,0 +1,89 @@
+package jwt
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+var (
+ ErrInvalidKey = errors.New("key is invalid")
+ ErrInvalidKeyType = errors.New("key is of invalid type")
+ ErrHashUnavailable = errors.New("the requested hash function is unavailable")
+ ErrTokenMalformed = errors.New("token is malformed")
+ ErrTokenUnverifiable = errors.New("token is unverifiable")
+ ErrTokenSignatureInvalid = errors.New("token signature is invalid")
+ ErrTokenRequiredClaimMissing = errors.New("token is missing required claim")
+ ErrTokenInvalidAudience = errors.New("token has invalid audience")
+ ErrTokenExpired = errors.New("token is expired")
+ ErrTokenUsedBeforeIssued = errors.New("token used before issued")
+ ErrTokenInvalidIssuer = errors.New("token has invalid issuer")
+ ErrTokenInvalidSubject = errors.New("token has invalid subject")
+ ErrTokenNotValidYet = errors.New("token is not valid yet")
+ ErrTokenInvalidId = errors.New("token has invalid id")
+ ErrTokenInvalidClaims = errors.New("token has invalid claims")
+ ErrInvalidType = errors.New("invalid type for claim")
+)
+
+// joinedError is an error type that works similar to what [errors.Join]
+// produces, with the exception that it has a nice error string; mainly its
+// error messages are concatenated using a comma, rather than a newline.
+type joinedError struct {
+ errs []error
+}
+
+func (je joinedError) Error() string {
+ msg := []string{}
+ for _, err := range je.errs {
+ msg = append(msg, err.Error())
+ }
+
+ return strings.Join(msg, ", ")
+}
+
+// joinErrors joins together multiple errors. Useful for scenarios where
+// multiple errors next to each other occur, e.g., in claims validation.
+func joinErrors(errs ...error) error {
+ return &joinedError{
+ errs: errs,
+ }
+}
+
+// Unwrap implements the multiple error unwrapping for this error type, which is
+// possible in Go 1.20.
+func (je joinedError) Unwrap() []error {
+ return je.errs
+}
+
+// newError creates a new error message with a detailed error message. The
+// message will be prefixed with the contents of the supplied error type.
+// Additionally, more errors, that provide more context can be supplied which
+// will be appended to the message. This makes use of Go 1.20's possibility to
+// include more than one %w formatting directive in [fmt.Errorf].
+//
+// For example,
+//
+// newError("no keyfunc was provided", ErrTokenUnverifiable)
+//
+// will produce the error string
+//
+// "token is unverifiable: no keyfunc was provided"
+func newError(message string, err error, more ...error) error {
+ var format string
+ var args []any
+ if message != "" {
+ format = "%w: %s"
+ args = []any{err, message}
+ } else {
+ format = "%w"
+ args = []any{err}
+ }
+
+ for _, e := range more {
+ format += ": %w"
+ args = append(args, e)
+ }
+
+ err = fmt.Errorf(format, args...)
+ return err
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/hmac.go b/vendor/github.com/golang-jwt/jwt/v5/hmac.go
new file mode 100644
index 000000000..1bef138c3
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/hmac.go
@@ -0,0 +1,104 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "errors"
+)
+
+// SigningMethodHMAC implements the HMAC-SHA family of signing methods.
+// Expects key type of []byte for both signing and validation
+type SigningMethodHMAC struct {
+ Name string
+ Hash crypto.Hash
+}
+
+// Specific instances for HS256 and company
+var (
+ SigningMethodHS256 *SigningMethodHMAC
+ SigningMethodHS384 *SigningMethodHMAC
+ SigningMethodHS512 *SigningMethodHMAC
+ ErrSignatureInvalid = errors.New("signature is invalid")
+)
+
+func init() {
+ // HS256
+ SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
+ RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
+ return SigningMethodHS256
+ })
+
+ // HS384
+ SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
+ RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
+ return SigningMethodHS384
+ })
+
+ // HS512
+ SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
+ RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
+ return SigningMethodHS512
+ })
+}
+
+func (m *SigningMethodHMAC) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod. Returns nil if
+// the signature is valid. Key must be []byte.
+//
+// Note it is not advised to provide a []byte which was converted from a 'human
+// readable' string using a subset of ASCII characters. To maximize entropy, you
+// should ideally be providing a []byte key which was produced from a
+// cryptographically random source, e.g. crypto/rand. Additional information
+// about this, and why we intentionally are not supporting string as a key can
+// be found on our usage guide
+// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types.
+func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key any) error {
+ // Verify the key is the right type
+ keyBytes, ok := key.([]byte)
+ if !ok {
+ return newError("HMAC verify expects []byte", ErrInvalidKeyType)
+ }
+
+ // Can we use the specified hashing method?
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+
+ // This signing method is symmetric, so we validate the signature
+ // by reproducing the signature from the signing string and key, then
+ // comparing that against the provided signature.
+ hasher := hmac.New(m.Hash.New, keyBytes)
+ hasher.Write([]byte(signingString))
+ if !hmac.Equal(sig, hasher.Sum(nil)) {
+ return ErrSignatureInvalid
+ }
+
+ // No validation errors. Signature is good.
+ return nil
+}
+
+// Sign implements token signing for the SigningMethod. Key must be []byte.
+//
+// Note it is not advised to provide a []byte which was converted from a 'human
+// readable' string using a subset of ASCII characters. To maximize entropy, you
+// should ideally be providing a []byte key which was produced from a
+// cryptographically random source, e.g. crypto/rand. Additional information
+// about this, and why we intentionally are not supporting string as a key can
+// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/.
+func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byte, error) {
+ if keyBytes, ok := key.([]byte); ok {
+ if !m.Hash.Available() {
+ return nil, ErrHashUnavailable
+ }
+
+ hasher := hmac.New(m.Hash.New, keyBytes)
+ hasher.Write([]byte(signingString))
+
+ return hasher.Sum(nil), nil
+ }
+
+ return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType)
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/map_claims.go b/vendor/github.com/golang-jwt/jwt/v5/map_claims.go
new file mode 100644
index 000000000..3b9205272
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/map_claims.go
@@ -0,0 +1,109 @@
+package jwt
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// MapClaims is a claims type that uses the map[string]any for JSON
+// decoding. This is the default claims type if you don't supply one
+type MapClaims map[string]any
+
+// GetExpirationTime implements the Claims interface.
+func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
+ return m.parseNumericDate("exp")
+}
+
+// GetNotBefore implements the Claims interface.
+func (m MapClaims) GetNotBefore() (*NumericDate, error) {
+ return m.parseNumericDate("nbf")
+}
+
+// GetIssuedAt implements the Claims interface.
+func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
+ return m.parseNumericDate("iat")
+}
+
+// GetAudience implements the Claims interface.
+func (m MapClaims) GetAudience() (ClaimStrings, error) {
+ return m.parseClaimsString("aud")
+}
+
+// GetIssuer implements the Claims interface.
+func (m MapClaims) GetIssuer() (string, error) {
+ return m.parseString("iss")
+}
+
+// GetSubject implements the Claims interface.
+func (m MapClaims) GetSubject() (string, error) {
+ return m.parseString("sub")
+}
+
+// parseNumericDate tries to parse a key in the map claims type as a number
+// date. This will succeed, if the underlying type is either a [float64] or a
+// [json.Number]. Otherwise, nil will be returned.
+func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
+ v, ok := m[key]
+ if !ok {
+ return nil, nil
+ }
+
+ switch exp := v.(type) {
+ case float64:
+ if exp == 0 {
+ return nil, nil
+ }
+
+ return newNumericDateFromSeconds(exp), nil
+ case json.Number:
+ v, _ := exp.Float64()
+
+ return newNumericDateFromSeconds(v), nil
+ }
+
+ return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
+}
+
+// parseClaimsString tries to parse a key in the map claims type as a
+// [ClaimsStrings] type, which can either be a string or an array of string.
+func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
+ var cs []string
+ switch v := m[key].(type) {
+ case string:
+ cs = append(cs, v)
+ case []string:
+ cs = v
+ case []any:
+ for _, a := range v {
+ vs, ok := a.(string)
+ if !ok {
+ return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
+ }
+ cs = append(cs, vs)
+ }
+ }
+
+ return cs, nil
+}
+
+// parseString tries to parse a key in the map claims type as a [string] type.
+// If the key does not exist, an empty string is returned. If the key has the
+// wrong type, an error is returned.
+func (m MapClaims) parseString(key string) (string, error) {
+ var (
+ ok bool
+ raw any
+ iss string
+ )
+ raw, ok = m[key]
+ if !ok {
+ return "", nil
+ }
+
+ iss, ok = raw.(string)
+ if !ok {
+ return "", newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
+ }
+
+ return iss, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/none.go b/vendor/github.com/golang-jwt/jwt/v5/none.go
new file mode 100644
index 000000000..624ad55e8
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/none.go
@@ -0,0 +1,50 @@
+package jwt
+
+// SigningMethodNone implements the none signing method. This is required by the spec
+// but you probably should never use it.
+var SigningMethodNone *signingMethodNone
+
+const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"
+
+var NoneSignatureTypeDisallowedError error
+
+type signingMethodNone struct{}
+type unsafeNoneMagicConstant string
+
+func init() {
+ SigningMethodNone = &signingMethodNone{}
+ NoneSignatureTypeDisallowedError = newError("'none' signature type is not allowed", ErrTokenUnverifiable)
+
+ RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
+ return SigningMethodNone
+ })
+}
+
+func (m *signingMethodNone) Alg() string {
+ return "none"
+}
+
+// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Verify(signingString string, sig []byte, key any) (err error) {
+ // Key must be UnsafeAllowNoneSignatureType to prevent accidentally
+ // accepting 'none' signing method
+ if _, ok := key.(unsafeNoneMagicConstant); !ok {
+ return NoneSignatureTypeDisallowedError
+ }
+ // If signing method is none, signature must be an empty string
+ if len(sig) != 0 {
+ return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable)
+ }
+
+ // Accept 'none' signing method.
+ return nil
+}
+
+// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Sign(signingString string, key any) ([]byte, error) {
+ if _, ok := key.(unsafeNoneMagicConstant); ok {
+ return []byte{}, nil
+ }
+
+ return nil, NoneSignatureTypeDisallowedError
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser.go b/vendor/github.com/golang-jwt/jwt/v5/parser.go
new file mode 100644
index 000000000..054c7eb6f
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/parser.go
@@ -0,0 +1,268 @@
+package jwt
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+const tokenDelimiter = "."
+
+type Parser struct {
+ // If populated, only these methods will be considered valid.
+ validMethods []string
+
+ // Use JSON Number format in JSON decoder.
+ useJSONNumber bool
+
+ // Skip claims validation during token parsing.
+ skipClaimsValidation bool
+
+ validator *Validator
+
+ decodeStrict bool
+
+ decodePaddingAllowed bool
+}
+
+// NewParser creates a new Parser with the specified options
+func NewParser(options ...ParserOption) *Parser {
+ p := &Parser{
+ validator: &Validator{},
+ }
+
+ // Loop through our parsing options and apply them
+ for _, option := range options {
+ option(p)
+ }
+
+ return p
+}
+
+// Parse parses, validates, verifies the signature and returns the parsed token.
+// keyFunc will receive the parsed token and should return the key for validating.
+func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
+ return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
+}
+
+// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
+// interface. This provides default values which can be overridden and allows a caller to use their own type, rather
+// than the default MapClaims implementation of Claims.
+//
+// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
+// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
+// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
+func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
+ token, parts, err := p.ParseUnverified(tokenString, claims)
+ if err != nil {
+ return token, err
+ }
+
+ // Verify signing method is in the required set
+ if p.validMethods != nil {
+ var signingMethodValid = false
+ var alg = token.Method.Alg()
+ for _, m := range p.validMethods {
+ if m == alg {
+ signingMethodValid = true
+ break
+ }
+ }
+ if !signingMethodValid {
+ // signing method is not in the listed set
+ return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
+ }
+ }
+
+ // Decode signature
+ token.Signature, err = p.DecodeSegment(parts[2])
+ if err != nil {
+ return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
+ }
+ text := strings.Join(parts[0:2], ".")
+
+ // Lookup key(s)
+ if keyFunc == nil {
+ // keyFunc was not provided. short circuiting validation
+ return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
+ }
+
+ got, err := keyFunc(token)
+ if err != nil {
+ return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
+ }
+
+ switch have := got.(type) {
+ case VerificationKeySet:
+ if len(have.Keys) == 0 {
+ return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
+ }
+ // Iterate through keys and verify signature, skipping the rest when a match is found.
+ // Return the last error if no match is found.
+ for _, key := range have.Keys {
+ if err = token.Method.Verify(text, token.Signature, key); err == nil {
+ break
+ }
+ }
+ default:
+ err = token.Method.Verify(text, token.Signature, have)
+ }
+ if err != nil {
+ return token, newError("", ErrTokenSignatureInvalid, err)
+ }
+
+ // Validate Claims
+ if !p.skipClaimsValidation {
+ // Make sure we have at least a default validator
+ if p.validator == nil {
+ p.validator = NewValidator()
+ }
+
+ if err := p.validator.Validate(claims); err != nil {
+ return token, newError("", ErrTokenInvalidClaims, err)
+ }
+ }
+
+ // No errors so far, token is valid.
+ token.Valid = true
+
+ return token, nil
+}
+
+// ParseUnverified parses the token but doesn't validate the signature.
+//
+// WARNING: Don't use this method unless you know what you're doing.
+//
+// It's only ever useful in cases where you know the signature is valid (since it has already
+// been or will be checked elsewhere in the stack) and you want to extract values from it.
+func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
+ var ok bool
+ parts, ok = splitToken(tokenString)
+ if !ok {
+ return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
+ }
+
+ token = &Token{Raw: tokenString}
+
+ // parse Header
+ var headerBytes []byte
+ if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
+ return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
+ }
+ if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
+ return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
+ }
+
+ // parse Claims
+ token.Claims = claims
+
+ claimBytes, err := p.DecodeSegment(parts[1])
+ if err != nil {
+ return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
+ }
+
+ // If `useJSONNumber` is enabled then we must use *json.Decoder to decode
+ // the claims. However, this comes with a performance penalty so only use
+ // it if we must and, otherwise, simple use json.Unmarshal.
+ if !p.useJSONNumber {
+ // JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
+ if c, ok := token.Claims.(MapClaims); ok {
+ err = json.Unmarshal(claimBytes, &c)
+ } else {
+ err = json.Unmarshal(claimBytes, &claims)
+ }
+ } else {
+ dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
+ dec.UseNumber()
+ // JSON Decode. Special case for map type to avoid weird pointer behavior.
+ if c, ok := token.Claims.(MapClaims); ok {
+ err = dec.Decode(&c)
+ } else {
+ err = dec.Decode(&claims)
+ }
+ }
+ if err != nil {
+ return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
+ }
+
+ // Lookup signature method
+ if method, ok := token.Header["alg"].(string); ok {
+ if token.Method = GetSigningMethod(method); token.Method == nil {
+ return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable)
+ }
+ } else {
+ return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
+ }
+
+ return token, parts, nil
+}
+
+// splitToken splits a token string into three parts: header, claims, and signature. It will only
+// return true if the token contains exactly two delimiters and three parts. In all other cases, it
+// will return nil parts and false.
+func splitToken(token string) ([]string, bool) {
+ parts := make([]string, 3)
+ header, remain, ok := strings.Cut(token, tokenDelimiter)
+ if !ok {
+ return nil, false
+ }
+ parts[0] = header
+ claims, remain, ok := strings.Cut(remain, tokenDelimiter)
+ if !ok {
+ return nil, false
+ }
+ parts[1] = claims
+ // One more cut to ensure the signature is the last part of the token and there are no more
+ // delimiters. This avoids an issue where malicious input could contain additional delimiters
+ // causing unecessary overhead parsing tokens.
+ signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
+ if unexpected {
+ return nil, false
+ }
+ parts[2] = signature
+
+ return parts, true
+}
+
+// DecodeSegment decodes a JWT specific base64url encoding. This function will
+// take into account whether the [Parser] is configured with additional options,
+// such as [WithStrictDecoding] or [WithPaddingAllowed].
+func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
+ encoding := base64.RawURLEncoding
+
+ if p.decodePaddingAllowed {
+ if l := len(seg) % 4; l > 0 {
+ seg += strings.Repeat("=", 4-l)
+ }
+ encoding = base64.URLEncoding
+ }
+
+ if p.decodeStrict {
+ encoding = encoding.Strict()
+ }
+ return encoding.DecodeString(seg)
+}
+
+// Parse parses, validates, verifies the signature and returns the parsed token.
+// keyFunc will receive the parsed token and should return the cryptographic key
+// for verifying the signature. The caller is strongly encouraged to set the
+// WithValidMethods option to validate the 'alg' claim in the token matches the
+// expected algorithm. For more details about the importance of validating the
+// 'alg' claim, see
+// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
+func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
+ return NewParser(options...).Parse(tokenString, keyFunc)
+}
+
+// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
+//
+// Note: If you provide a custom claim implementation that embeds one of the
+// standard claims (such as RegisteredClaims), make sure that a) you either
+// embed a non-pointer version of the claims or b) if you are using a pointer,
+// allocate the proper memory for it before passing in the overall claims,
+// otherwise you might run into a panic.
+func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
+ return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser_option.go b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go
new file mode 100644
index 000000000..431573557
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go
@@ -0,0 +1,145 @@
+package jwt
+
+import "time"
+
+// ParserOption is used to implement functional-style options that modify the
+// behavior of the parser. To add new options, just create a function (ideally
+// beginning with With or Without) that returns an anonymous function that takes
+// a *Parser type as input and manipulates its configuration accordingly.
+type ParserOption func(*Parser)
+
+// WithValidMethods is an option to supply algorithm methods that the parser
+// will check. Only those methods will be considered valid. It is heavily
+// encouraged to use this option in order to prevent attacks such as
+// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
+func WithValidMethods(methods []string) ParserOption {
+ return func(p *Parser) {
+ p.validMethods = methods
+ }
+}
+
+// WithJSONNumber is an option to configure the underlying JSON parser with
+// UseNumber.
+func WithJSONNumber() ParserOption {
+ return func(p *Parser) {
+ p.useJSONNumber = true
+ }
+}
+
+// WithoutClaimsValidation is an option to disable claims validation. This
+// option should only be used if you exactly know what you are doing.
+func WithoutClaimsValidation() ParserOption {
+ return func(p *Parser) {
+ p.skipClaimsValidation = true
+ }
+}
+
+// WithLeeway returns the ParserOption for specifying the leeway window.
+func WithLeeway(leeway time.Duration) ParserOption {
+ return func(p *Parser) {
+ p.validator.leeway = leeway
+ }
+}
+
+// WithTimeFunc returns the ParserOption for specifying the time func. The
+// primary use-case for this is testing. If you are looking for a way to account
+// for clock-skew, WithLeeway should be used instead.
+func WithTimeFunc(f func() time.Time) ParserOption {
+ return func(p *Parser) {
+ p.validator.timeFunc = f
+ }
+}
+
+// WithIssuedAt returns the ParserOption to enable verification
+// of issued-at.
+func WithIssuedAt() ParserOption {
+ return func(p *Parser) {
+ p.validator.verifyIat = true
+ }
+}
+
+// WithExpirationRequired returns the ParserOption to make exp claim required.
+// By default exp claim is optional.
+func WithExpirationRequired() ParserOption {
+ return func(p *Parser) {
+ p.validator.requireExp = true
+ }
+}
+
+// WithAudience configures the validator to require any of the specified
+// audiences in the `aud` claim. Validation will fail if the audience is not
+// listed in the token or the `aud` claim is missing.
+//
+// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
+// application-specific. Since this validation API is helping developers in
+// writing secure application, we decided to REQUIRE the existence of the claim,
+// if an audience is expected.
+func WithAudience(aud ...string) ParserOption {
+ return func(p *Parser) {
+ p.validator.expectedAud = aud
+ }
+}
+
+// WithAllAudiences configures the validator to require all the specified
+// audiences in the `aud` claim. Validation will fail if the specified audiences
+// are not listed in the token or the `aud` claim is missing. Duplicates within
+// the list are de-duplicated since internally, we use a map to look up the
+// audiences.
+//
+// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
+// application-specific. Since this validation API is helping developers in
+// writing secure application, we decided to REQUIRE the existence of the claim,
+// if an audience is expected.
+func WithAllAudiences(aud ...string) ParserOption {
+ return func(p *Parser) {
+ p.validator.expectedAud = aud
+ p.validator.expectAllAud = true
+ }
+}
+
+// WithIssuer configures the validator to require the specified issuer in the
+// `iss` claim. Validation will fail if a different issuer is specified in the
+// token or the `iss` claim is missing.
+//
+// NOTE: While the `iss` claim is OPTIONAL in a JWT, the handling of it is
+// application-specific. Since this validation API is helping developers in
+// writing secure application, we decided to REQUIRE the existence of the claim,
+// if an issuer is expected.
+func WithIssuer(iss string) ParserOption {
+ return func(p *Parser) {
+ p.validator.expectedIss = iss
+ }
+}
+
+// WithSubject configures the validator to require the specified subject in the
+// `sub` claim. Validation will fail if a different subject is specified in the
+// token or the `sub` claim is missing.
+//
+// NOTE: While the `sub` claim is OPTIONAL in a JWT, the handling of it is
+// application-specific. Since this validation API is helping developers in
+// writing secure application, we decided to REQUIRE the existence of the claim,
+// if a subject is expected.
+func WithSubject(sub string) ParserOption {
+ return func(p *Parser) {
+ p.validator.expectedSub = sub
+ }
+}
+
+// WithPaddingAllowed will enable the codec used for decoding JWTs to allow
+// padding. Note that the JWS RFC7515 states that the tokens will utilize a
+// Base64url encoding with no padding. Unfortunately, some implementations of
+// JWT are producing non-standard tokens, and thus require support for decoding.
+func WithPaddingAllowed() ParserOption {
+ return func(p *Parser) {
+ p.decodePaddingAllowed = true
+ }
+}
+
+// WithStrictDecoding will switch the codec used for decoding JWTs into strict
+// mode. In this mode, the decoder requires that trailing padding bits are zero,
+// as described in RFC 4648 section 3.5.
+func WithStrictDecoding() ParserOption {
+ return func(p *Parser) {
+ p.decodeStrict = true
+ }
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go b/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go
new file mode 100644
index 000000000..77951a531
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go
@@ -0,0 +1,63 @@
+package jwt
+
+// RegisteredClaims are a structured version of the JWT Claims Set,
+// restricted to Registered Claim Names, as referenced at
+// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
+//
+// This type can be used on its own, but then additional private and
+// public claims embedded in the JWT will not be parsed. The typical use-case
+// therefore is to embedded this in a user-defined claim type.
+//
+// See examples for how to use this with your own claim types.
+type RegisteredClaims struct {
+ // the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
+ Issuer string `json:"iss,omitempty"`
+
+ // the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
+ Subject string `json:"sub,omitempty"`
+
+ // the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
+ Audience ClaimStrings `json:"aud,omitempty"`
+
+ // the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
+ ExpiresAt *NumericDate `json:"exp,omitempty"`
+
+ // the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
+ NotBefore *NumericDate `json:"nbf,omitempty"`
+
+ // the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
+ IssuedAt *NumericDate `json:"iat,omitempty"`
+
+ // the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
+ ID string `json:"jti,omitempty"`
+}
+
+// GetExpirationTime implements the Claims interface.
+func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error) {
+ return c.ExpiresAt, nil
+}
+
+// GetNotBefore implements the Claims interface.
+func (c RegisteredClaims) GetNotBefore() (*NumericDate, error) {
+ return c.NotBefore, nil
+}
+
+// GetIssuedAt implements the Claims interface.
+func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error) {
+ return c.IssuedAt, nil
+}
+
+// GetAudience implements the Claims interface.
+func (c RegisteredClaims) GetAudience() (ClaimStrings, error) {
+ return c.Audience, nil
+}
+
+// GetIssuer implements the Claims interface.
+func (c RegisteredClaims) GetIssuer() (string, error) {
+ return c.Issuer, nil
+}
+
+// GetSubject implements the Claims interface.
+func (c RegisteredClaims) GetSubject() (string, error) {
+ return c.Subject, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/rsa.go b/vendor/github.com/golang-jwt/jwt/v5/rsa.go
new file mode 100644
index 000000000..98b960a78
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/rsa.go
@@ -0,0 +1,93 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// SigningMethodRSA implements the RSA family of signing methods.
+// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
+type SigningMethodRSA struct {
+ Name string
+ Hash crypto.Hash
+}
+
+// Specific instances for RS256 and company
+var (
+ SigningMethodRS256 *SigningMethodRSA
+ SigningMethodRS384 *SigningMethodRSA
+ SigningMethodRS512 *SigningMethodRSA
+)
+
+func init() {
+ // RS256
+ SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
+ RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
+ return SigningMethodRS256
+ })
+
+ // RS384
+ SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
+ RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
+ return SigningMethodRS384
+ })
+
+ // RS512
+ SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
+ RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
+ return SigningMethodRS512
+ })
+}
+
+func (m *SigningMethodRSA) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod
+// For this signing method, must be an *rsa.PublicKey structure.
+func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key any) error {
+ var rsaKey *rsa.PublicKey
+ var ok bool
+
+ if rsaKey, ok = key.(*rsa.PublicKey); !ok {
+ return newError("RSA verify expects *rsa.PublicKey", ErrInvalidKeyType)
+ }
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Verify the signature
+ return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
+}
+
+// Sign implements token signing for the SigningMethod
+// For this signing method, must be an *rsa.PrivateKey structure.
+func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte, error) {
+ var rsaKey *rsa.PrivateKey
+ var ok bool
+
+ // Validate type of key
+ if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
+ return nil, newError("RSA sign expects *rsa.PrivateKey", ErrInvalidKeyType)
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return nil, ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return the encoded bytes
+ if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
+ return sigBytes, nil
+ } else {
+ return nil, err
+ }
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go
new file mode 100644
index 000000000..f17590cc4
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go
@@ -0,0 +1,132 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
+type SigningMethodRSAPSS struct {
+ *SigningMethodRSA
+ Options *rsa.PSSOptions
+ // VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS.
+ // Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow
+ // https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously.
+ // See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details.
+ VerifyOptions *rsa.PSSOptions
+}
+
+// Specific instances for RS/PS and company.
+var (
+ SigningMethodPS256 *SigningMethodRSAPSS
+ SigningMethodPS384 *SigningMethodRSAPSS
+ SigningMethodPS512 *SigningMethodRSAPSS
+)
+
+func init() {
+ // PS256
+ SigningMethodPS256 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS256",
+ Hash: crypto.SHA256,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
+ return SigningMethodPS256
+ })
+
+ // PS384
+ SigningMethodPS384 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS384",
+ Hash: crypto.SHA384,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
+ return SigningMethodPS384
+ })
+
+ // PS512
+ SigningMethodPS512 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS512",
+ Hash: crypto.SHA512,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
+ return SigningMethodPS512
+ })
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an rsa.PublicKey struct
+func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key any) error {
+ var rsaKey *rsa.PublicKey
+ switch k := key.(type) {
+ case *rsa.PublicKey:
+ rsaKey = k
+ default:
+ return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType)
+ }
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ opts := m.Options
+ if m.VerifyOptions != nil {
+ opts = m.VerifyOptions
+ }
+
+ return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an rsa.PrivateKey struct
+func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]byte, error) {
+ var rsaKey *rsa.PrivateKey
+
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ rsaKey = k
+ default:
+ return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType)
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return nil, ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return the encoded bytes
+ if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
+ return sigBytes, nil
+ } else {
+ return nil, err
+ }
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go b/vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go
new file mode 100644
index 000000000..f22c3d068
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go
@@ -0,0 +1,107 @@
+package jwt
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key")
+ ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key")
+ ErrNotRSAPublicKey = errors.New("key is not a valid RSA public key")
+)
+
+// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key
+func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ var parsedKey any
+ if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *rsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+ return nil, ErrNotRSAPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password
+//
+// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock
+// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative
+// in the Go standard library for now. See https://github.com/golang/go/issues/8860.
+func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ var parsedKey any
+
+ var blockDecrypted []byte
+ if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
+ return nil, err
+ }
+
+ if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *rsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+ return nil, ErrNotRSAPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseRSAPublicKeyFromPEM parses a certificate or a PEM encoded PKCS1 or PKIX public key
+func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey any
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+ parsedKey = cert.PublicKey
+ } else {
+ if parsedKey, err = x509.ParsePKCS1PublicKey(block.Bytes); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ var pkey *rsa.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
+ return nil, ErrNotRSAPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/signing_method.go b/vendor/github.com/golang-jwt/jwt/v5/signing_method.go
new file mode 100644
index 000000000..096d0ed4c
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/signing_method.go
@@ -0,0 +1,49 @@
+package jwt
+
+import (
+ "sync"
+)
+
+var signingMethods = map[string]func() SigningMethod{}
+var signingMethodLock = new(sync.RWMutex)
+
+// SigningMethod can be used add new methods for signing or verifying tokens. It
+// takes a decoded signature as an input in the Verify function and produces a
+// signature in Sign. The signature is then usually base64 encoded as part of a
+// JWT.
+type SigningMethod interface {
+ Verify(signingString string, sig []byte, key any) error // Returns nil if signature is valid
+ Sign(signingString string, key any) ([]byte, error) // Returns signature or error
+ Alg() string // returns the alg identifier for this method (example: 'HS256')
+}
+
+// RegisterSigningMethod registers the "alg" name and a factory function for signing method.
+// This is typically done during init() in the method's implementation
+func RegisterSigningMethod(alg string, f func() SigningMethod) {
+ signingMethodLock.Lock()
+ defer signingMethodLock.Unlock()
+
+ signingMethods[alg] = f
+}
+
+// GetSigningMethod retrieves a signing method from an "alg" string
+func GetSigningMethod(alg string) (method SigningMethod) {
+ signingMethodLock.RLock()
+ defer signingMethodLock.RUnlock()
+
+ if methodF, ok := signingMethods[alg]; ok {
+ method = methodF()
+ }
+ return
+}
+
+// GetAlgorithms returns a list of registered "alg" names
+func GetAlgorithms() (algs []string) {
+ signingMethodLock.RLock()
+ defer signingMethodLock.RUnlock()
+
+ for alg := range signingMethods {
+ algs = append(algs, alg)
+ }
+ return
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf b/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf
new file mode 100644
index 000000000..53745d51d
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf
@@ -0,0 +1 @@
+checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"]
diff --git a/vendor/github.com/golang-jwt/jwt/v5/token.go b/vendor/github.com/golang-jwt/jwt/v5/token.go
new file mode 100644
index 000000000..3f7155888
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/token.go
@@ -0,0 +1,100 @@
+package jwt
+
+import (
+ "crypto"
+ "encoding/base64"
+ "encoding/json"
+)
+
+// Keyfunc will be used by the Parse methods as a callback function to supply
+// the key for verification. The function receives the parsed, but unverified
+// Token. This allows you to use properties in the Header of the token (such as
+// `kid`) to identify which key to use.
+//
+// The returned any may be a single key or a VerificationKeySet containing
+// multiple keys.
+type Keyfunc func(*Token) (any, error)
+
+// VerificationKey represents a public or secret key for verifying a token's signature.
+type VerificationKey interface {
+ crypto.PublicKey | []uint8
+}
+
+// VerificationKeySet is a set of public or secret keys. It is used by the parser to verify a token.
+type VerificationKeySet struct {
+ Keys []VerificationKey
+}
+
+// Token represents a JWT Token. Different fields will be used depending on
+// whether you're creating or parsing/verifying a token.
+type Token struct {
+ Raw string // Raw contains the raw token. Populated when you [Parse] a token
+ Method SigningMethod // Method is the signing method used or to be used
+ Header map[string]any // Header is the first segment of the token in decoded form
+ Claims Claims // Claims is the second segment of the token in decoded form
+ Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token
+ Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
+}
+
+// New creates a new [Token] with the specified signing method and an empty map
+// of claims. Additional options can be specified, but are currently unused.
+func New(method SigningMethod, opts ...TokenOption) *Token {
+ return NewWithClaims(method, MapClaims{}, opts...)
+}
+
+// NewWithClaims creates a new [Token] with the specified signing method and
+// claims. Additional options can be specified, but are currently unused.
+func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token {
+ return &Token{
+ Header: map[string]any{
+ "typ": "JWT",
+ "alg": method.Alg(),
+ },
+ Claims: claims,
+ Method: method,
+ }
+}
+
+// SignedString creates and returns a complete, signed JWT. The token is signed
+// using the SigningMethod specified in the token. Please refer to
+// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types
+// for an overview of the different signing methods and their respective key
+// types.
+func (t *Token) SignedString(key any) (string, error) {
+ sstr, err := t.SigningString()
+ if err != nil {
+ return "", err
+ }
+
+ sig, err := t.Method.Sign(sstr, key)
+ if err != nil {
+ return "", err
+ }
+
+ return sstr + "." + t.EncodeSegment(sig), nil
+}
+
+// SigningString generates the signing string. This is the most expensive part
+// of the whole deal. Unless you need this for something special, just go
+// straight for the SignedString.
+func (t *Token) SigningString() (string, error) {
+ h, err := json.Marshal(t.Header)
+ if err != nil {
+ return "", err
+ }
+
+ c, err := json.Marshal(t.Claims)
+ if err != nil {
+ return "", err
+ }
+
+ return t.EncodeSegment(h) + "." + t.EncodeSegment(c), nil
+}
+
+// EncodeSegment encodes a JWT specific base64url encoding with padding
+// stripped. In the future, this function might take into account a
+// [TokenOption]. Therefore, this function exists as a method of [Token], rather
+// than a global function.
+func (*Token) EncodeSegment(seg []byte) string {
+ return base64.RawURLEncoding.EncodeToString(seg)
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/token_option.go b/vendor/github.com/golang-jwt/jwt/v5/token_option.go
new file mode 100644
index 000000000..b4ae3badf
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/token_option.go
@@ -0,0 +1,5 @@
+package jwt
+
+// TokenOption is a reserved type, which provides some forward compatibility,
+// if we ever want to introduce token creation-related options.
+type TokenOption func(*Token)
diff --git a/vendor/github.com/golang-jwt/jwt/v5/types.go b/vendor/github.com/golang-jwt/jwt/v5/types.go
new file mode 100644
index 000000000..a3e0ef121
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/types.go
@@ -0,0 +1,149 @@
+package jwt
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+ "strconv"
+ "time"
+)
+
+// TimePrecision sets the precision of times and dates within this library. This
+// has an influence on the precision of times when comparing expiry or other
+// related time fields. Furthermore, it is also the precision of times when
+// serializing.
+//
+// For backwards compatibility the default precision is set to seconds, so that
+// no fractional timestamps are generated.
+var TimePrecision = time.Second
+
+// MarshalSingleStringAsArray modifies the behavior of the ClaimStrings type,
+// especially its MarshalJSON function.
+//
+// If it is set to true (the default), it will always serialize the type as an
+// array of strings, even if it just contains one element, defaulting to the
+// behavior of the underlying []string. If it is set to false, it will serialize
+// to a single string, if it contains one element. Otherwise, it will serialize
+// to an array of strings.
+var MarshalSingleStringAsArray = true
+
+// NumericDate represents a JSON numeric date value, as referenced at
+// https://datatracker.ietf.org/doc/html/rfc7519#section-2.
+type NumericDate struct {
+ time.Time
+}
+
+// NewNumericDate constructs a new *NumericDate from a standard library time.Time struct.
+// It will truncate the timestamp according to the precision specified in TimePrecision.
+func NewNumericDate(t time.Time) *NumericDate {
+ return &NumericDate{t.Truncate(TimePrecision)}
+}
+
+// newNumericDateFromSeconds creates a new *NumericDate out of a float64 representing a
+// UNIX epoch with the float fraction representing non-integer seconds.
+func newNumericDateFromSeconds(f float64) *NumericDate {
+ round, frac := math.Modf(f)
+ return NewNumericDate(time.Unix(int64(round), int64(frac*1e9)))
+}
+
+// MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch
+// represented in NumericDate to a byte array, using the precision specified in TimePrecision.
+func (date NumericDate) MarshalJSON() (b []byte, err error) {
+ var prec int
+ if TimePrecision < time.Second {
+ prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
+ }
+ truncatedDate := date.Truncate(TimePrecision)
+
+ // For very large timestamps, UnixNano would overflow an int64, but this
+ // function requires nanosecond level precision, so we have to use the
+ // following technique to get round the issue:
+ //
+ // 1. Take the normal unix timestamp to form the whole number part of the
+ // output,
+ // 2. Take the result of the Nanosecond function, which returns the offset
+ // within the second of the particular unix time instance, to form the
+ // decimal part of the output
+ // 3. Concatenate them to produce the final result
+ seconds := strconv.FormatInt(truncatedDate.Unix(), 10)
+ nanosecondsOffset := strconv.FormatFloat(float64(truncatedDate.Nanosecond())/float64(time.Second), 'f', prec, 64)
+
+ output := append([]byte(seconds), []byte(nanosecondsOffset)[1:]...)
+
+ return output, nil
+}
+
+// UnmarshalJSON is an implementation of the json.RawMessage interface and
+// deserializes a [NumericDate] from a JSON representation, i.e. a
+// [json.Number]. This number represents an UNIX epoch with either integer or
+// non-integer seconds.
+func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
+ var (
+ number json.Number
+ f float64
+ )
+
+ if err = json.Unmarshal(b, &number); err != nil {
+ return fmt.Errorf("could not parse NumericData: %w", err)
+ }
+
+ if f, err = number.Float64(); err != nil {
+ return fmt.Errorf("could not convert json number value to float: %w", err)
+ }
+
+ n := newNumericDateFromSeconds(f)
+ *date = *n
+
+ return nil
+}
+
+// ClaimStrings is basically just a slice of strings, but it can be either
+// serialized from a string array or just a string. This type is necessary,
+// since the "aud" claim can either be a single string or an array.
+type ClaimStrings []string
+
+func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
+ var value any
+
+ if err = json.Unmarshal(data, &value); err != nil {
+ return err
+ }
+
+ var aud []string
+
+ switch v := value.(type) {
+ case string:
+ aud = append(aud, v)
+ case []string:
+ aud = ClaimStrings(v)
+ case []any:
+ for _, vv := range v {
+ vs, ok := vv.(string)
+ if !ok {
+ return ErrInvalidType
+ }
+ aud = append(aud, vs)
+ }
+ case nil:
+ return nil
+ default:
+ return ErrInvalidType
+ }
+
+ *s = aud
+
+ return
+}
+
+func (s ClaimStrings) MarshalJSON() (b []byte, err error) {
+ // This handles a special case in the JWT RFC. If the string array, e.g.
+ // used by the "aud" field, only contains one element, it MAY be serialized
+ // as a single string. This may or may not be desired based on the ecosystem
+ // of other JWT library used, so we make it configurable by the variable
+ // MarshalSingleStringAsArray.
+ if len(s) == 1 && !MarshalSingleStringAsArray {
+ return json.Marshal(s[0])
+ }
+
+ return json.Marshal([]string(s))
+}
diff --git a/vendor/github.com/golang-jwt/jwt/v5/validator.go b/vendor/github.com/golang-jwt/jwt/v5/validator.go
new file mode 100644
index 000000000..92b5c057c
--- /dev/null
+++ b/vendor/github.com/golang-jwt/jwt/v5/validator.go
@@ -0,0 +1,326 @@
+package jwt
+
+import (
+ "fmt"
+ "slices"
+ "time"
+)
+
+// ClaimsValidator is an interface that can be implemented by custom claims who
+// wish to execute any additional claims validation based on
+// application-specific logic. The Validate function is then executed in
+// addition to the regular claims validation and any error returned is appended
+// to the final validation result.
+//
+// type MyCustomClaims struct {
+// Foo string `json:"foo"`
+// jwt.RegisteredClaims
+// }
+//
+// func (m MyCustomClaims) Validate() error {
+// if m.Foo != "bar" {
+// return errors.New("must be foobar")
+// }
+// return nil
+// }
+type ClaimsValidator interface {
+ Claims
+ Validate() error
+}
+
+// Validator is the core of the new Validation API. It is automatically used by
+// a [Parser] during parsing and can be modified with various parser options.
+//
+// The [NewValidator] function should be used to create an instance of this
+// struct.
+type Validator struct {
+ // leeway is an optional leeway that can be provided to account for clock skew.
+ leeway time.Duration
+
+ // timeFunc is used to supply the current time that is needed for
+ // validation. If unspecified, this defaults to time.Now.
+ timeFunc func() time.Time
+
+ // requireExp specifies whether the exp claim is required
+ requireExp bool
+
+ // verifyIat specifies whether the iat (Issued At) claim will be verified.
+ // According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
+ // only specifies the age of the token, but no validation check is
+ // necessary. However, if wanted, it can be checked if the iat is
+ // unrealistic, i.e., in the future.
+ verifyIat bool
+
+ // expectedAud contains the audience this token expects. Supplying an empty
+ // slice will disable aud checking.
+ expectedAud []string
+
+ // expectAllAud specifies whether all expected audiences must be present in
+ // the token. If false, only one of the expected audiences must be present.
+ expectAllAud bool
+
+ // expectedIss contains the issuer this token expects. Supplying an empty
+ // string will disable iss checking.
+ expectedIss string
+
+ // expectedSub contains the subject this token expects. Supplying an empty
+ // string will disable sub checking.
+ expectedSub string
+}
+
+// NewValidator can be used to create a stand-alone validator with the supplied
+// options. This validator can then be used to validate already parsed claims.
+//
+// Note: Under normal circumstances, explicitly creating a validator is not
+// needed and can potentially be dangerous; instead functions of the [Parser]
+// class should be used.
+//
+// The [Validator] is only checking the *validity* of the claims, such as its
+// expiration time, but it does NOT perform *signature verification* of the
+// token.
+func NewValidator(opts ...ParserOption) *Validator {
+ p := NewParser(opts...)
+ return p.validator
+}
+
+// Validate validates the given claims. It will also perform any custom
+// validation if claims implements the [ClaimsValidator] interface.
+//
+// Note: It will NOT perform any *signature verification* on the token that
+// contains the claims and expects that the [Claim] was already successfully
+// verified.
+func (v *Validator) Validate(claims Claims) error {
+ var (
+ now time.Time
+ errs = make([]error, 0, 6)
+ err error
+ )
+
+ // Check, if we have a time func
+ if v.timeFunc != nil {
+ now = v.timeFunc()
+ } else {
+ now = time.Now()
+ }
+
+ // We always need to check the expiration time, but usage of the claim
+ // itself is OPTIONAL by default. requireExp overrides this behavior
+ // and makes the exp claim mandatory.
+ if err = v.verifyExpiresAt(claims, now, v.requireExp); err != nil {
+ errs = append(errs, err)
+ }
+
+ // We always need to check not-before, but usage of the claim itself is
+ // OPTIONAL.
+ if err = v.verifyNotBefore(claims, now, false); err != nil {
+ errs = append(errs, err)
+ }
+
+ // Check issued-at if the option is enabled
+ if v.verifyIat {
+ if err = v.verifyIssuedAt(claims, now, false); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ // If we have an expected audience, we also require the audience claim
+ if len(v.expectedAud) > 0 {
+ if err = v.verifyAudience(claims, v.expectedAud, v.expectAllAud); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ // If we have an expected issuer, we also require the issuer claim
+ if v.expectedIss != "" {
+ if err = v.verifyIssuer(claims, v.expectedIss, true); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ // If we have an expected subject, we also require the subject claim
+ if v.expectedSub != "" {
+ if err = v.verifySubject(claims, v.expectedSub, true); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ // Finally, we want to give the claim itself some possibility to do some
+ // additional custom validation based on a custom Validate function.
+ cvt, ok := claims.(ClaimsValidator)
+ if ok {
+ if err := cvt.Validate(); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ if len(errs) == 0 {
+ return nil
+ }
+
+ return joinErrors(errs...)
+}
+
+// verifyExpiresAt compares the exp claim in claims against cmp. This function
+// will succeed if cmp < exp. Additional leeway is taken into account.
+//
+// If exp is not set, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error {
+ exp, err := claims.GetExpirationTime()
+ if err != nil {
+ return err
+ }
+
+ if exp == nil {
+ return errorIfRequired(required, "exp")
+ }
+
+ return errorIfFalse(cmp.Before((exp.Time).Add(+v.leeway)), ErrTokenExpired)
+}
+
+// verifyIssuedAt compares the iat claim in claims against cmp. This function
+// will succeed if cmp >= iat. Additional leeway is taken into account.
+//
+// If iat is not set, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error {
+ iat, err := claims.GetIssuedAt()
+ if err != nil {
+ return err
+ }
+
+ if iat == nil {
+ return errorIfRequired(required, "iat")
+ }
+
+ return errorIfFalse(!cmp.Before(iat.Add(-v.leeway)), ErrTokenUsedBeforeIssued)
+}
+
+// verifyNotBefore compares the nbf claim in claims against cmp. This function
+// will return true if cmp >= nbf. Additional leeway is taken into account.
+//
+// If nbf is not set, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error {
+ nbf, err := claims.GetNotBefore()
+ if err != nil {
+ return err
+ }
+
+ if nbf == nil {
+ return errorIfRequired(required, "nbf")
+ }
+
+ return errorIfFalse(!cmp.Before(nbf.Add(-v.leeway)), ErrTokenNotValidYet)
+}
+
+// verifyAudience compares the aud claim against cmp.
+//
+// If aud is not set or an empty list, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifyAudience(claims Claims, cmp []string, expectAllAud bool) error {
+ aud, err := claims.GetAudience()
+ if err != nil {
+ return err
+ }
+
+ // Check that aud exists and is not empty. We only require the aud claim
+ // if we expect at least one audience to be present.
+ if len(aud) == 0 || len(aud) == 1 && aud[0] == "" {
+ required := len(v.expectedAud) > 0
+ return errorIfRequired(required, "aud")
+ }
+
+ if !expectAllAud {
+ for _, a := range aud {
+ // If we only expect one match, we can stop early if we find a match
+ if slices.Contains(cmp, a) {
+ return nil
+ }
+ }
+
+ return ErrTokenInvalidAudience
+ }
+
+ // Note that we are looping cmp here to ensure that all expected audiences
+ // are present in the aud claim.
+ for _, a := range cmp {
+ if !slices.Contains(aud, a) {
+ return ErrTokenInvalidAudience
+ }
+ }
+
+ return nil
+}
+
+// verifyIssuer compares the iss claim in claims against cmp.
+//
+// If iss is not set, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifyIssuer(claims Claims, cmp string, required bool) error {
+ iss, err := claims.GetIssuer()
+ if err != nil {
+ return err
+ }
+
+ if iss == "" {
+ return errorIfRequired(required, "iss")
+ }
+
+ return errorIfFalse(iss == cmp, ErrTokenInvalidIssuer)
+}
+
+// verifySubject compares the sub claim against cmp.
+//
+// If sub is not set, it will succeed if the claim is not required,
+// otherwise ErrTokenRequiredClaimMissing will be returned.
+//
+// Additionally, if any error occurs while retrieving the claim, e.g., when its
+// the wrong type, an ErrTokenUnverifiable error will be returned.
+func (v *Validator) verifySubject(claims Claims, cmp string, required bool) error {
+ sub, err := claims.GetSubject()
+ if err != nil {
+ return err
+ }
+
+ if sub == "" {
+ return errorIfRequired(required, "sub")
+ }
+
+ return errorIfFalse(sub == cmp, ErrTokenInvalidSubject)
+}
+
+// errorIfFalse returns the error specified in err, if the value is true.
+// Otherwise, nil is returned.
+func errorIfFalse(value bool, err error) error {
+ if value {
+ return nil
+ } else {
+ return err
+ }
+}
+
+// errorIfRequired returns an ErrTokenRequiredClaimMissing error if required is
+// true. Otherwise, nil is returned.
+func errorIfRequired(required bool, claim string) error {
+ if required {
+ return newError(fmt.Sprintf("%s claim is required", claim), ErrTokenRequiredClaimMissing)
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/kylelemons/godebug/LICENSE b/vendor/github.com/kylelemons/godebug/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/kylelemons/godebug/diff/diff.go b/vendor/github.com/kylelemons/godebug/diff/diff.go
new file mode 100644
index 000000000..200e596c6
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/diff/diff.go
@@ -0,0 +1,186 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// 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 diff implements a linewise diff algorithm.
+package diff
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// Chunk represents a piece of the diff. A chunk will not have both added and
+// deleted lines. Equal lines are always after any added or deleted lines.
+// A Chunk may or may not have any lines in it, especially for the first or last
+// chunk in a computation.
+type Chunk struct {
+ Added []string
+ Deleted []string
+ Equal []string
+}
+
+func (c *Chunk) empty() bool {
+ return len(c.Added) == 0 && len(c.Deleted) == 0 && len(c.Equal) == 0
+}
+
+// Diff returns a string containing a line-by-line unified diff of the linewise
+// changes required to make A into B. Each line is prefixed with '+', '-', or
+// ' ' to indicate if it should be added, removed, or is correct respectively.
+func Diff(A, B string) string {
+ aLines := strings.Split(A, "\n")
+ bLines := strings.Split(B, "\n")
+
+ chunks := DiffChunks(aLines, bLines)
+
+ buf := new(bytes.Buffer)
+ for _, c := range chunks {
+ for _, line := range c.Added {
+ fmt.Fprintf(buf, "+%s\n", line)
+ }
+ for _, line := range c.Deleted {
+ fmt.Fprintf(buf, "-%s\n", line)
+ }
+ for _, line := range c.Equal {
+ fmt.Fprintf(buf, " %s\n", line)
+ }
+ }
+ return strings.TrimRight(buf.String(), "\n")
+}
+
+// DiffChunks uses an O(D(N+M)) shortest-edit-script algorithm
+// to compute the edits required from A to B and returns the
+// edit chunks.
+func DiffChunks(a, b []string) []Chunk {
+ // algorithm: http://www.xmailserver.org/diff2.pdf
+
+ // We'll need these quantities a lot.
+ alen, blen := len(a), len(b) // M, N
+
+ // At most, it will require len(a) deletions and len(b) additions
+ // to transform a into b.
+ maxPath := alen + blen // MAX
+ if maxPath == 0 {
+ // degenerate case: two empty lists are the same
+ return nil
+ }
+
+ // Store the endpoint of the path for diagonals.
+ // We store only the a index, because the b index on any diagonal
+ // (which we know during the loop below) is aidx-diag.
+ // endpoint[maxPath] represents the 0 diagonal.
+ //
+ // Stated differently:
+ // endpoint[d] contains the aidx of a furthest reaching path in diagonal d
+ endpoint := make([]int, 2*maxPath+1) // V
+
+ saved := make([][]int, 0, 8) // Vs
+ save := func() {
+ dup := make([]int, len(endpoint))
+ copy(dup, endpoint)
+ saved = append(saved, dup)
+ }
+
+ var editDistance int // D
+dLoop:
+ for editDistance = 0; editDistance <= maxPath; editDistance++ {
+ // The 0 diag(onal) represents equality of a and b. Each diagonal to
+ // the left is numbered one lower, to the right is one higher, from
+ // -alen to +blen. Negative diagonals favor differences from a,
+ // positive diagonals favor differences from b. The edit distance to a
+ // diagonal d cannot be shorter than d itself.
+ //
+ // The iterations of this loop cover either odds or evens, but not both,
+ // If odd indices are inputs, even indices are outputs and vice versa.
+ for diag := -editDistance; diag <= editDistance; diag += 2 { // k
+ var aidx int // x
+ switch {
+ case diag == -editDistance:
+ // This is a new diagonal; copy from previous iter
+ aidx = endpoint[maxPath-editDistance+1] + 0
+ case diag == editDistance:
+ // This is a new diagonal; copy from previous iter
+ aidx = endpoint[maxPath+editDistance-1] + 1
+ case endpoint[maxPath+diag+1] > endpoint[maxPath+diag-1]:
+ // diagonal d+1 was farther along, so use that
+ aidx = endpoint[maxPath+diag+1] + 0
+ default:
+ // diagonal d-1 was farther (or the same), so use that
+ aidx = endpoint[maxPath+diag-1] + 1
+ }
+ // On diagonal d, we can compute bidx from aidx.
+ bidx := aidx - diag // y
+ // See how far we can go on this diagonal before we find a difference.
+ for aidx < alen && bidx < blen && a[aidx] == b[bidx] {
+ aidx++
+ bidx++
+ }
+ // Store the end of the current edit chain.
+ endpoint[maxPath+diag] = aidx
+ // If we've found the end of both inputs, we're done!
+ if aidx >= alen && bidx >= blen {
+ save() // save the final path
+ break dLoop
+ }
+ }
+ save() // save the current path
+ }
+ if editDistance == 0 {
+ return nil
+ }
+ chunks := make([]Chunk, editDistance+1)
+
+ x, y := alen, blen
+ for d := editDistance; d > 0; d-- {
+ endpoint := saved[d]
+ diag := x - y
+ insert := diag == -d || (diag != d && endpoint[maxPath+diag-1] < endpoint[maxPath+diag+1])
+
+ x1 := endpoint[maxPath+diag]
+ var x0, xM, kk int
+ if insert {
+ kk = diag + 1
+ x0 = endpoint[maxPath+kk]
+ xM = x0
+ } else {
+ kk = diag - 1
+ x0 = endpoint[maxPath+kk]
+ xM = x0 + 1
+ }
+ y0 := x0 - kk
+
+ var c Chunk
+ if insert {
+ c.Added = b[y0:][:1]
+ } else {
+ c.Deleted = a[x0:][:1]
+ }
+ if xM < x1 {
+ c.Equal = a[xM:][:x1-xM]
+ }
+
+ x, y = x0, y0
+ chunks[d] = c
+ }
+ if x > 0 {
+ chunks[0].Equal = a[:x]
+ }
+ if chunks[0].empty() {
+ chunks = chunks[1:]
+ }
+ if len(chunks) == 0 {
+ return nil
+ }
+ return chunks
+}
diff --git a/vendor/github.com/kylelemons/godebug/pretty/.gitignore b/vendor/github.com/kylelemons/godebug/pretty/.gitignore
new file mode 100644
index 000000000..fa9a735da
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/pretty/.gitignore
@@ -0,0 +1,5 @@
+*.test
+*.bench
+*.golden
+*.txt
+*.prof
diff --git a/vendor/github.com/kylelemons/godebug/pretty/doc.go b/vendor/github.com/kylelemons/godebug/pretty/doc.go
new file mode 100644
index 000000000..03b5718a7
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/pretty/doc.go
@@ -0,0 +1,25 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// 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 pretty pretty-prints Go structures.
+//
+// This package uses reflection to examine a Go value and can
+// print out in a nice, aligned fashion. It supports three
+// modes (normal, compact, and extended) for advanced use.
+//
+// See the Reflect and Print examples for what the output looks like.
+package pretty
+
+// TODO:
+// - Catch cycles
diff --git a/vendor/github.com/kylelemons/godebug/pretty/public.go b/vendor/github.com/kylelemons/godebug/pretty/public.go
new file mode 100644
index 000000000..fbc5d7abb
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/pretty/public.go
@@ -0,0 +1,188 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// 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 pretty
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net"
+ "reflect"
+ "time"
+
+ "github.com/kylelemons/godebug/diff"
+)
+
+// A Config represents optional configuration parameters for formatting.
+//
+// Some options, notably ShortList, dramatically increase the overhead
+// of pretty-printing a value.
+type Config struct {
+ // Verbosity options
+ Compact bool // One-line output. Overrides Diffable.
+ Diffable bool // Adds extra newlines for more easily diffable output.
+
+ // Field and value options
+ IncludeUnexported bool // Include unexported fields in output
+ PrintStringers bool // Call String on a fmt.Stringer
+ PrintTextMarshalers bool // Call MarshalText on an encoding.TextMarshaler
+ SkipZeroFields bool // Skip struct fields that have a zero value.
+
+ // Output transforms
+ ShortList int // Maximum character length for short lists if nonzero.
+
+ // Type-specific overrides
+ //
+ // Formatter maps a type to a function that will provide a one-line string
+ // representation of the input value. Conceptually:
+ // Formatter[reflect.TypeOf(v)](v) = "v as a string"
+ //
+ // Note that the first argument need not explicitly match the type, it must
+ // merely be callable with it.
+ //
+ // When processing an input value, if its type exists as a key in Formatter:
+ // 1) If the value is nil, no stringification is performed.
+ // This allows overriding of PrintStringers and PrintTextMarshalers.
+ // 2) The value will be called with the input as its only argument.
+ // The function must return a string as its first return value.
+ //
+ // In addition to func literals, two common values for this will be:
+ // fmt.Sprint (function) func Sprint(...interface{}) string
+ // Type.String (method) func (Type) String() string
+ //
+ // Note that neither of these work if the String method is a pointer
+ // method and the input will be provided as a value. In that case,
+ // use a function that calls .String on the formal value parameter.
+ Formatter map[reflect.Type]interface{}
+
+ // If TrackCycles is enabled, pretty will detect and track
+ // self-referential structures. If a self-referential structure (aka a
+ // "recursive" value) is detected, numbered placeholders will be emitted.
+ //
+ // Pointer tracking is disabled by default for performance reasons.
+ TrackCycles bool
+}
+
+// Default Config objects
+var (
+ // DefaultFormatter is the default set of overrides for stringification.
+ DefaultFormatter = map[reflect.Type]interface{}{
+ reflect.TypeOf(time.Time{}): fmt.Sprint,
+ reflect.TypeOf(net.IP{}): fmt.Sprint,
+ reflect.TypeOf((*error)(nil)).Elem(): fmt.Sprint,
+ }
+
+ // CompareConfig is the default configuration used for Compare.
+ CompareConfig = &Config{
+ Diffable: true,
+ IncludeUnexported: true,
+ Formatter: DefaultFormatter,
+ }
+
+ // DefaultConfig is the default configuration used for all other top-level functions.
+ DefaultConfig = &Config{
+ Formatter: DefaultFormatter,
+ }
+
+ // CycleTracker is a convenience config for formatting and comparing recursive structures.
+ CycleTracker = &Config{
+ Diffable: true,
+ Formatter: DefaultFormatter,
+ TrackCycles: true,
+ }
+)
+
+func (cfg *Config) fprint(buf *bytes.Buffer, vals ...interface{}) {
+ ref := &reflector{
+ Config: cfg,
+ }
+ if cfg.TrackCycles {
+ ref.pointerTracker = new(pointerTracker)
+ }
+ for i, val := range vals {
+ if i > 0 {
+ buf.WriteByte('\n')
+ }
+ newFormatter(cfg, buf).write(ref.val2node(reflect.ValueOf(val)))
+ }
+}
+
+// Print writes the DefaultConfig representation of the given values to standard output.
+func Print(vals ...interface{}) {
+ DefaultConfig.Print(vals...)
+}
+
+// Print writes the configured presentation of the given values to standard output.
+func (cfg *Config) Print(vals ...interface{}) {
+ fmt.Println(cfg.Sprint(vals...))
+}
+
+// Sprint returns a string representation of the given value according to the DefaultConfig.
+func Sprint(vals ...interface{}) string {
+ return DefaultConfig.Sprint(vals...)
+}
+
+// Sprint returns a string representation of the given value according to cfg.
+func (cfg *Config) Sprint(vals ...interface{}) string {
+ buf := new(bytes.Buffer)
+ cfg.fprint(buf, vals...)
+ return buf.String()
+}
+
+// Fprint writes the representation of the given value to the writer according to the DefaultConfig.
+func Fprint(w io.Writer, vals ...interface{}) (n int64, err error) {
+ return DefaultConfig.Fprint(w, vals...)
+}
+
+// Fprint writes the representation of the given value to the writer according to the cfg.
+func (cfg *Config) Fprint(w io.Writer, vals ...interface{}) (n int64, err error) {
+ buf := new(bytes.Buffer)
+ cfg.fprint(buf, vals...)
+ return buf.WriteTo(w)
+}
+
+// Compare returns a string containing a line-by-line unified diff of the
+// values in a and b, using the CompareConfig.
+//
+// Each line in the output is prefixed with '+', '-', or ' ' to indicate which
+// side it's from. Lines from the a side are marked with '-', lines from the
+// b side are marked with '+' and lines that are the same on both sides are
+// marked with ' '.
+//
+// The comparison is based on the intentionally-untyped output of Print, and as
+// such this comparison is pretty forviving. In particular, if the types of or
+// types within in a and b are different but have the same representation,
+// Compare will not indicate any differences between them.
+func Compare(a, b interface{}) string {
+ return CompareConfig.Compare(a, b)
+}
+
+// Compare returns a string containing a line-by-line unified diff of the
+// values in got and want according to the cfg.
+//
+// Each line in the output is prefixed with '+', '-', or ' ' to indicate which
+// side it's from. Lines from the a side are marked with '-', lines from the
+// b side are marked with '+' and lines that are the same on both sides are
+// marked with ' '.
+//
+// The comparison is based on the intentionally-untyped output of Print, and as
+// such this comparison is pretty forviving. In particular, if the types of or
+// types within in a and b are different but have the same representation,
+// Compare will not indicate any differences between them.
+func (cfg *Config) Compare(a, b interface{}) string {
+ diffCfg := *cfg
+ diffCfg.Diffable = true
+ return diff.Diff(cfg.Sprint(a), cfg.Sprint(b))
+}
diff --git a/vendor/github.com/kylelemons/godebug/pretty/reflect.go b/vendor/github.com/kylelemons/godebug/pretty/reflect.go
new file mode 100644
index 000000000..5cd30b7f0
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/pretty/reflect.go
@@ -0,0 +1,241 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// 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 pretty
+
+import (
+ "encoding"
+ "fmt"
+ "reflect"
+ "sort"
+)
+
+func isZeroVal(val reflect.Value) bool {
+ if !val.CanInterface() {
+ return false
+ }
+ z := reflect.Zero(val.Type()).Interface()
+ return reflect.DeepEqual(val.Interface(), z)
+}
+
+// pointerTracker is a helper for tracking pointer chasing to detect cycles.
+type pointerTracker struct {
+ addrs map[uintptr]int // addr[address] = seen count
+
+ lastID int
+ ids map[uintptr]int // ids[address] = id
+}
+
+// track tracks following a reference (pointer, slice, map, etc). Every call to
+// track should be paired with a call to untrack.
+func (p *pointerTracker) track(ptr uintptr) {
+ if p.addrs == nil {
+ p.addrs = make(map[uintptr]int)
+ }
+ p.addrs[ptr]++
+}
+
+// untrack registers that we have backtracked over the reference to the pointer.
+func (p *pointerTracker) untrack(ptr uintptr) {
+ p.addrs[ptr]--
+ if p.addrs[ptr] == 0 {
+ delete(p.addrs, ptr)
+ }
+}
+
+// seen returns whether the pointer was previously seen along this path.
+func (p *pointerTracker) seen(ptr uintptr) bool {
+ _, ok := p.addrs[ptr]
+ return ok
+}
+
+// keep allocates an ID for the given address and returns it.
+func (p *pointerTracker) keep(ptr uintptr) int {
+ if p.ids == nil {
+ p.ids = make(map[uintptr]int)
+ }
+ if _, ok := p.ids[ptr]; !ok {
+ p.lastID++
+ p.ids[ptr] = p.lastID
+ }
+ return p.ids[ptr]
+}
+
+// id returns the ID for the given address.
+func (p *pointerTracker) id(ptr uintptr) (int, bool) {
+ if p.ids == nil {
+ p.ids = make(map[uintptr]int)
+ }
+ id, ok := p.ids[ptr]
+ return id, ok
+}
+
+// reflector adds local state to the recursive reflection logic.
+type reflector struct {
+ *Config
+ *pointerTracker
+}
+
+// follow handles following a possiblly-recursive reference to the given value
+// from the given ptr address.
+func (r *reflector) follow(ptr uintptr, val reflect.Value) node {
+ if r.pointerTracker == nil {
+ // Tracking disabled
+ return r.val2node(val)
+ }
+
+ // If a parent already followed this, emit a reference marker
+ if r.seen(ptr) {
+ id := r.keep(ptr)
+ return ref{id}
+ }
+
+ // Track the pointer we're following while on this recursive branch
+ r.track(ptr)
+ defer r.untrack(ptr)
+ n := r.val2node(val)
+
+ // If the recursion used this ptr, wrap it with a target marker
+ if id, ok := r.id(ptr); ok {
+ return target{id, n}
+ }
+
+ // Otherwise, return the node unadulterated
+ return n
+}
+
+func (r *reflector) val2node(val reflect.Value) node {
+ if !val.IsValid() {
+ return rawVal("nil")
+ }
+
+ if val.CanInterface() {
+ v := val.Interface()
+ if formatter, ok := r.Formatter[val.Type()]; ok {
+ if formatter != nil {
+ res := reflect.ValueOf(formatter).Call([]reflect.Value{val})
+ return rawVal(res[0].Interface().(string))
+ }
+ } else {
+ if s, ok := v.(fmt.Stringer); ok && r.PrintStringers {
+ return stringVal(s.String())
+ }
+ if t, ok := v.(encoding.TextMarshaler); ok && r.PrintTextMarshalers {
+ if raw, err := t.MarshalText(); err == nil { // if NOT an error
+ return stringVal(string(raw))
+ }
+ }
+ }
+ }
+
+ switch kind := val.Kind(); kind {
+ case reflect.Ptr:
+ if val.IsNil() {
+ return rawVal("nil")
+ }
+ return r.follow(val.Pointer(), val.Elem())
+ case reflect.Interface:
+ if val.IsNil() {
+ return rawVal("nil")
+ }
+ return r.val2node(val.Elem())
+ case reflect.String:
+ return stringVal(val.String())
+ case reflect.Slice:
+ n := list{}
+ length := val.Len()
+ ptr := val.Pointer()
+ for i := 0; i < length; i++ {
+ n = append(n, r.follow(ptr, val.Index(i)))
+ }
+ return n
+ case reflect.Array:
+ n := list{}
+ length := val.Len()
+ for i := 0; i < length; i++ {
+ n = append(n, r.val2node(val.Index(i)))
+ }
+ return n
+ case reflect.Map:
+ // Extract the keys and sort them for stable iteration
+ keys := val.MapKeys()
+ pairs := make([]mapPair, 0, len(keys))
+ for _, key := range keys {
+ pairs = append(pairs, mapPair{
+ key: new(formatter).compactString(r.val2node(key)), // can't be cyclic
+ value: val.MapIndex(key),
+ })
+ }
+ sort.Sort(byKey(pairs))
+
+ // Process the keys into the final representation
+ ptr, n := val.Pointer(), keyvals{}
+ for _, pair := range pairs {
+ n = append(n, keyval{
+ key: pair.key,
+ val: r.follow(ptr, pair.value),
+ })
+ }
+ return n
+ case reflect.Struct:
+ n := keyvals{}
+ typ := val.Type()
+ fields := typ.NumField()
+ for i := 0; i < fields; i++ {
+ sf := typ.Field(i)
+ if !r.IncludeUnexported && sf.PkgPath != "" {
+ continue
+ }
+ field := val.Field(i)
+ if r.SkipZeroFields && isZeroVal(field) {
+ continue
+ }
+ n = append(n, keyval{sf.Name, r.val2node(field)})
+ }
+ return n
+ case reflect.Bool:
+ if val.Bool() {
+ return rawVal("true")
+ }
+ return rawVal("false")
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rawVal(fmt.Sprintf("%d", val.Int()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return rawVal(fmt.Sprintf("%d", val.Uint()))
+ case reflect.Uintptr:
+ return rawVal(fmt.Sprintf("0x%X", val.Uint()))
+ case reflect.Float32, reflect.Float64:
+ return rawVal(fmt.Sprintf("%v", val.Float()))
+ case reflect.Complex64, reflect.Complex128:
+ return rawVal(fmt.Sprintf("%v", val.Complex()))
+ }
+
+ // Fall back to the default %#v if we can
+ if val.CanInterface() {
+ return rawVal(fmt.Sprintf("%#v", val.Interface()))
+ }
+
+ return rawVal(val.String())
+}
+
+type mapPair struct {
+ key string
+ value reflect.Value
+}
+
+type byKey []mapPair
+
+func (v byKey) Len() int { return len(v) }
+func (v byKey) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
+func (v byKey) Less(i, j int) bool { return v[i].key < v[j].key }
diff --git a/vendor/github.com/kylelemons/godebug/pretty/structure.go b/vendor/github.com/kylelemons/godebug/pretty/structure.go
new file mode 100644
index 000000000..d876f60ca
--- /dev/null
+++ b/vendor/github.com/kylelemons/godebug/pretty/structure.go
@@ -0,0 +1,223 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// 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 pretty
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// a formatter stores stateful formatting information as well as being
+// an io.Writer for simplicity.
+type formatter struct {
+ *bufio.Writer
+ *Config
+
+ // Self-referential structure tracking
+ tagNumbers map[int]int // tagNumbers[id] = <#n>
+}
+
+// newFormatter creates a new buffered formatter. For the output to be written
+// to the given writer, this must be accompanied by a call to write (or Flush).
+func newFormatter(cfg *Config, w io.Writer) *formatter {
+ return &formatter{
+ Writer: bufio.NewWriter(w),
+ Config: cfg,
+ tagNumbers: make(map[int]int),
+ }
+}
+
+func (f *formatter) write(n node) {
+ defer f.Flush()
+ n.format(f, "")
+}
+
+func (f *formatter) tagFor(id int) int {
+ if tag, ok := f.tagNumbers[id]; ok {
+ return tag
+ }
+ if f.tagNumbers == nil {
+ return 0
+ }
+ tag := len(f.tagNumbers) + 1
+ f.tagNumbers[id] = tag
+ return tag
+}
+
+type node interface {
+ format(f *formatter, indent string)
+}
+
+func (f *formatter) compactString(n node) string {
+ switch k := n.(type) {
+ case stringVal:
+ return string(k)
+ case rawVal:
+ return string(k)
+ }
+
+ buf := new(bytes.Buffer)
+ f2 := newFormatter(&Config{Compact: true}, buf)
+ f2.tagNumbers = f.tagNumbers // reuse tagNumbers just in case
+ f2.write(n)
+ return buf.String()
+}
+
+type stringVal string
+
+func (str stringVal) format(f *formatter, indent string) {
+ f.WriteString(strconv.Quote(string(str)))
+}
+
+type rawVal string
+
+func (r rawVal) format(f *formatter, indent string) {
+ f.WriteString(string(r))
+}
+
+type keyval struct {
+ key string
+ val node
+}
+
+type keyvals []keyval
+
+func (l keyvals) format(f *formatter, indent string) {
+ f.WriteByte('{')
+
+ switch {
+ case f.Compact:
+ // All on one line:
+ for i, kv := range l {
+ if i > 0 {
+ f.WriteByte(',')
+ }
+ f.WriteString(kv.key)
+ f.WriteByte(':')
+ kv.val.format(f, indent)
+ }
+ case f.Diffable:
+ f.WriteByte('\n')
+ inner := indent + " "
+ // Each value gets its own line:
+ for _, kv := range l {
+ f.WriteString(inner)
+ f.WriteString(kv.key)
+ f.WriteString(": ")
+ kv.val.format(f, inner)
+ f.WriteString(",\n")
+ }
+ f.WriteString(indent)
+ default:
+ keyWidth := 0
+ for _, kv := range l {
+ if kw := len(kv.key); kw > keyWidth {
+ keyWidth = kw
+ }
+ }
+ alignKey := indent + " "
+ alignValue := strings.Repeat(" ", keyWidth)
+ inner := alignKey + alignValue + " "
+ // First and last line shared with bracket:
+ for i, kv := range l {
+ if i > 0 {
+ f.WriteString(",\n")
+ f.WriteString(alignKey)
+ }
+ f.WriteString(kv.key)
+ f.WriteString(": ")
+ f.WriteString(alignValue[len(kv.key):])
+ kv.val.format(f, inner)
+ }
+ }
+
+ f.WriteByte('}')
+}
+
+type list []node
+
+func (l list) format(f *formatter, indent string) {
+ if max := f.ShortList; max > 0 {
+ short := f.compactString(l)
+ if len(short) <= max {
+ f.WriteString(short)
+ return
+ }
+ }
+
+ f.WriteByte('[')
+
+ switch {
+ case f.Compact:
+ // All on one line:
+ for i, v := range l {
+ if i > 0 {
+ f.WriteByte(',')
+ }
+ v.format(f, indent)
+ }
+ case f.Diffable:
+ f.WriteByte('\n')
+ inner := indent + " "
+ // Each value gets its own line:
+ for _, v := range l {
+ f.WriteString(inner)
+ v.format(f, inner)
+ f.WriteString(",\n")
+ }
+ f.WriteString(indent)
+ default:
+ inner := indent + " "
+ // First and last line shared with bracket:
+ for i, v := range l {
+ if i > 0 {
+ f.WriteString(",\n")
+ f.WriteString(inner)
+ }
+ v.format(f, inner)
+ }
+ }
+
+ f.WriteByte(']')
+}
+
+type ref struct {
+ id int
+}
+
+func (r ref) format(f *formatter, indent string) {
+ fmt.Fprintf(f, "", f.tagFor(r.id))
+}
+
+type target struct {
+ id int
+ value node
+}
+
+func (t target) format(f *formatter, indent string) {
+ tag := fmt.Sprintf("<#%d> ", f.tagFor(t.id))
+ switch {
+ case f.Diffable, f.Compact:
+ // no indent changes
+ default:
+ indent += strings.Repeat(" ", len(tag))
+ }
+ f.WriteString(tag)
+ t.value.format(f, indent)
+}
diff --git a/vendor/github.com/pkg/browser/LICENSE b/vendor/github.com/pkg/browser/LICENSE
new file mode 100644
index 000000000..65f78fb62
--- /dev/null
+++ b/vendor/github.com/pkg/browser/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2014, Dave Cheney
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pkg/browser/README.md b/vendor/github.com/pkg/browser/README.md
new file mode 100644
index 000000000..72b1976e3
--- /dev/null
+++ b/vendor/github.com/pkg/browser/README.md
@@ -0,0 +1,55 @@
+
+# browser
+ import "github.com/pkg/browser"
+
+Package browser provides helpers to open files, readers, and urls in a browser window.
+
+The choice of which browser is started is entirely client dependant.
+
+
+
+
+
+## Variables
+``` go
+var Stderr io.Writer = os.Stderr
+```
+Stderr is the io.Writer to which executed commands write standard error.
+
+``` go
+var Stdout io.Writer = os.Stdout
+```
+Stdout is the io.Writer to which executed commands write standard output.
+
+
+## func OpenFile
+``` go
+func OpenFile(path string) error
+```
+OpenFile opens new browser window for the file path.
+
+
+## func OpenReader
+``` go
+func OpenReader(r io.Reader) error
+```
+OpenReader consumes the contents of r and presents the
+results in a new browser window.
+
+
+## func OpenURL
+``` go
+func OpenURL(url string) error
+```
+OpenURL opens a new browser window pointing to url.
+
+
+
+
+
+
+
+
+
+- - -
+Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
diff --git a/vendor/github.com/pkg/browser/browser.go b/vendor/github.com/pkg/browser/browser.go
new file mode 100644
index 000000000..d7969d74d
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser.go
@@ -0,0 +1,57 @@
+// Package browser provides helpers to open files, readers, and urls in a browser window.
+//
+// The choice of which browser is started is entirely client dependant.
+package browser
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+)
+
+// Stdout is the io.Writer to which executed commands write standard output.
+var Stdout io.Writer = os.Stdout
+
+// Stderr is the io.Writer to which executed commands write standard error.
+var Stderr io.Writer = os.Stderr
+
+// OpenFile opens new browser window for the file path.
+func OpenFile(path string) error {
+ path, err := filepath.Abs(path)
+ if err != nil {
+ return err
+ }
+ return OpenURL("file://" + path)
+}
+
+// OpenReader consumes the contents of r and presents the
+// results in a new browser window.
+func OpenReader(r io.Reader) error {
+ f, err := ioutil.TempFile("", "browser.*.html")
+ if err != nil {
+ return fmt.Errorf("browser: could not create temporary file: %v", err)
+ }
+ if _, err := io.Copy(f, r); err != nil {
+ f.Close()
+ return fmt.Errorf("browser: caching temporary file failed: %v", err)
+ }
+ if err := f.Close(); err != nil {
+ return fmt.Errorf("browser: caching temporary file failed: %v", err)
+ }
+ return OpenFile(f.Name())
+}
+
+// OpenURL opens a new browser window pointing to url.
+func OpenURL(url string) error {
+ return openBrowser(url)
+}
+
+func runCmd(prog string, args ...string) error {
+ cmd := exec.Command(prog, args...)
+ cmd.Stdout = Stdout
+ cmd.Stderr = Stderr
+ return cmd.Run()
+}
diff --git a/vendor/github.com/pkg/browser/browser_darwin.go b/vendor/github.com/pkg/browser/browser_darwin.go
new file mode 100644
index 000000000..8507cf7c2
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_darwin.go
@@ -0,0 +1,5 @@
+package browser
+
+func openBrowser(url string) error {
+ return runCmd("open", url)
+}
diff --git a/vendor/github.com/pkg/browser/browser_freebsd.go b/vendor/github.com/pkg/browser/browser_freebsd.go
new file mode 100644
index 000000000..4fc7ff076
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_freebsd.go
@@ -0,0 +1,14 @@
+package browser
+
+import (
+ "errors"
+ "os/exec"
+)
+
+func openBrowser(url string) error {
+ err := runCmd("xdg-open", url)
+ if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
+ return errors.New("xdg-open: command not found - install xdg-utils from ports(8)")
+ }
+ return err
+}
diff --git a/vendor/github.com/pkg/browser/browser_linux.go b/vendor/github.com/pkg/browser/browser_linux.go
new file mode 100644
index 000000000..d26cdddf9
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_linux.go
@@ -0,0 +1,21 @@
+package browser
+
+import (
+ "os/exec"
+ "strings"
+)
+
+func openBrowser(url string) error {
+ providers := []string{"xdg-open", "x-www-browser", "www-browser"}
+
+ // There are multiple possible providers to open a browser on linux
+ // One of them is xdg-open, another is x-www-browser, then there's www-browser, etc.
+ // Look for one that exists and run it
+ for _, provider := range providers {
+ if _, err := exec.LookPath(provider); err == nil {
+ return runCmd(provider, url)
+ }
+ }
+
+ return &exec.Error{Name: strings.Join(providers, ","), Err: exec.ErrNotFound}
+}
diff --git a/vendor/github.com/pkg/browser/browser_netbsd.go b/vendor/github.com/pkg/browser/browser_netbsd.go
new file mode 100644
index 000000000..65a5e5a29
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_netbsd.go
@@ -0,0 +1,14 @@
+package browser
+
+import (
+ "errors"
+ "os/exec"
+)
+
+func openBrowser(url string) error {
+ err := runCmd("xdg-open", url)
+ if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
+ return errors.New("xdg-open: command not found - install xdg-utils from pkgsrc(7)")
+ }
+ return err
+}
diff --git a/vendor/github.com/pkg/browser/browser_openbsd.go b/vendor/github.com/pkg/browser/browser_openbsd.go
new file mode 100644
index 000000000..4fc7ff076
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_openbsd.go
@@ -0,0 +1,14 @@
+package browser
+
+import (
+ "errors"
+ "os/exec"
+)
+
+func openBrowser(url string) error {
+ err := runCmd("xdg-open", url)
+ if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
+ return errors.New("xdg-open: command not found - install xdg-utils from ports(8)")
+ }
+ return err
+}
diff --git a/vendor/github.com/pkg/browser/browser_unsupported.go b/vendor/github.com/pkg/browser/browser_unsupported.go
new file mode 100644
index 000000000..7c5c17d34
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_unsupported.go
@@ -0,0 +1,12 @@
+// +build !linux,!windows,!darwin,!openbsd,!freebsd,!netbsd
+
+package browser
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func openBrowser(url string) error {
+ return fmt.Errorf("openBrowser: unsupported operating system: %v", runtime.GOOS)
+}
diff --git a/vendor/github.com/pkg/browser/browser_windows.go b/vendor/github.com/pkg/browser/browser_windows.go
new file mode 100644
index 000000000..63e192959
--- /dev/null
+++ b/vendor/github.com/pkg/browser/browser_windows.go
@@ -0,0 +1,7 @@
+package browser
+
+import "golang.org/x/sys/windows"
+
+func openBrowser(url string) error {
+ return windows.ShellExecute(0, nil, windows.StringToUTF16Ptr(url), nil, nil, windows.SW_SHOWNORMAL)
+}
diff --git a/vendor/golang.org/x/crypto/LICENSE b/vendor/golang.org/x/crypto/LICENSE
new file mode 100644
index 000000000..2a7cf70da
--- /dev/null
+++ b/vendor/golang.org/x/crypto/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 The Go Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google LLC nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/golang.org/x/crypto/PATENTS b/vendor/golang.org/x/crypto/PATENTS
new file mode 100644
index 000000000..733099041
--- /dev/null
+++ b/vendor/golang.org/x/crypto/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/crypto/pkcs12/bmp-string.go b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go
new file mode 100644
index 000000000..233b8b62c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go
@@ -0,0 +1,50 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "errors"
+ "unicode/utf16"
+)
+
+// bmpString returns s encoded in UCS-2 with a zero terminator.
+func bmpString(s string) ([]byte, error) {
+ // References:
+ // https://tools.ietf.org/html/rfc7292#appendix-B.1
+ // https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
+ // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
+ // EncodeRune returns 0xfffd if the rune does not need special encoding
+ // - the above RFC provides the info that BMPStrings are NULL terminated.
+
+ ret := make([]byte, 0, 2*len(s)+2)
+
+ for _, r := range s {
+ if t, _ := utf16.EncodeRune(r); t != 0xfffd {
+ return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
+ }
+ ret = append(ret, byte(r/256), byte(r%256))
+ }
+
+ return append(ret, 0, 0), nil
+}
+
+func decodeBMPString(bmpString []byte) (string, error) {
+ if len(bmpString)%2 != 0 {
+ return "", errors.New("pkcs12: odd-length BMP string")
+ }
+
+ // strip terminator if present
+ if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
+ bmpString = bmpString[:l-2]
+ }
+
+ s := make([]uint16, 0, len(bmpString)/2)
+ for len(bmpString) > 0 {
+ s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
+ bmpString = bmpString[2:]
+ }
+
+ return string(utf16.Decode(s)), nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/crypto.go b/vendor/golang.org/x/crypto/pkcs12/crypto.go
new file mode 100644
index 000000000..212538cb5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/crypto.go
@@ -0,0 +1,131 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+
+ "golang.org/x/crypto/pkcs12/internal/rc2"
+)
+
+var (
+ oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
+ oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
+)
+
+// pbeCipher is an abstraction of a PKCS#12 cipher.
+type pbeCipher interface {
+ // create returns a cipher.Block given a key.
+ create(key []byte) (cipher.Block, error)
+ // deriveKey returns a key derived from the given password and salt.
+ deriveKey(salt, password []byte, iterations int) []byte
+ // deriveIV returns an IV derived from the given password and salt.
+ deriveIV(salt, password []byte, iterations int) []byte
+}
+
+type shaWithTripleDESCBC struct{}
+
+func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
+ return des.NewTripleDESCipher(key)
+}
+
+func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
+}
+
+func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type shaWith40BitRC2CBC struct{}
+
+func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
+ return rc2.New(key, len(key)*8)
+}
+
+func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
+}
+
+func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type pbeParams struct {
+ Salt []byte
+ Iterations int
+}
+
+func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
+ var cipherType pbeCipher
+
+ switch {
+ case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
+ cipherType = shaWithTripleDESCBC{}
+ case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
+ cipherType = shaWith40BitRC2CBC{}
+ default:
+ return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
+ }
+
+ var params pbeParams
+ if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil {
+ return nil, 0, err
+ }
+
+ key := cipherType.deriveKey(params.Salt, password, params.Iterations)
+ iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
+
+ block, err := cipherType.create(key)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
+}
+
+func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
+ cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
+ if err != nil {
+ return nil, err
+ }
+
+ encrypted := info.Data()
+ if len(encrypted) == 0 {
+ return nil, errors.New("pkcs12: empty encrypted data")
+ }
+ if len(encrypted)%blockSize != 0 {
+ return nil, errors.New("pkcs12: input is not a multiple of the block size")
+ }
+ decrypted = make([]byte, len(encrypted))
+ cbc.CryptBlocks(decrypted, encrypted)
+
+ psLen := int(decrypted[len(decrypted)-1])
+ if psLen == 0 || psLen > blockSize {
+ return nil, ErrDecryption
+ }
+
+ if len(decrypted) < psLen {
+ return nil, ErrDecryption
+ }
+ ps := decrypted[len(decrypted)-psLen:]
+ decrypted = decrypted[:len(decrypted)-psLen]
+ if !bytes.Equal(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) {
+ return nil, ErrDecryption
+ }
+
+ return
+}
+
+// decryptable abstracts an object that contains ciphertext.
+type decryptable interface {
+ Algorithm() pkix.AlgorithmIdentifier
+ Data() []byte
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/errors.go b/vendor/golang.org/x/crypto/pkcs12/errors.go
new file mode 100644
index 000000000..7377ce6fb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/errors.go
@@ -0,0 +1,23 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import "errors"
+
+var (
+ // ErrDecryption represents a failure to decrypt the input.
+ ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
+
+ // ErrIncorrectPassword is returned when an incorrect password is detected.
+ // Usually, P12/PFX data is signed to be able to verify the password.
+ ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
+)
+
+// NotImplementedError indicates that the input is not currently supported.
+type NotImplementedError string
+
+func (e NotImplementedError) Error() string {
+ return "pkcs12: " + string(e)
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go
new file mode 100644
index 000000000..05de9cc2c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go
@@ -0,0 +1,268 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rc2 implements the RC2 cipher
+/*
+https://www.ietf.org/rfc/rfc2268.txt
+http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
+
+This code is licensed under the MIT license.
+*/
+package rc2
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+ "math/bits"
+)
+
+// The rc2 block size in bytes
+const BlockSize = 8
+
+type rc2Cipher struct {
+ k [64]uint16
+}
+
+// New returns a new rc2 cipher with the given key and effective key length t1
+func New(key []byte, t1 int) (cipher.Block, error) {
+ // TODO(dgryski): error checking for key length
+ return &rc2Cipher{
+ k: expandKey(key, t1),
+ }, nil
+}
+
+func (*rc2Cipher) BlockSize() int { return BlockSize }
+
+var piTable = [256]byte{
+ 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
+ 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
+ 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
+ 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
+ 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
+ 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
+ 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
+ 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
+ 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
+ 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
+ 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
+ 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
+ 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
+ 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
+ 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
+ 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
+}
+
+func expandKey(key []byte, t1 int) [64]uint16 {
+
+ l := make([]byte, 128)
+ copy(l, key)
+
+ var t = len(key)
+ var t8 = (t1 + 7) / 8
+ var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8))))
+
+ for i := len(key); i < 128; i++ {
+ l[i] = piTable[l[i-1]+l[uint8(i-t)]]
+ }
+
+ l[128-t8] = piTable[l[128-t8]&tm]
+
+ for i := 127 - t8; i >= 0; i-- {
+ l[i] = piTable[l[i+1]^l[i+t8]]
+ }
+
+ var k [64]uint16
+
+ for i := range k {
+ k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256
+ }
+
+ return k
+}
+
+func (c *rc2Cipher) Encrypt(dst, src []byte) {
+
+ r0 := binary.LittleEndian.Uint16(src[0:])
+ r1 := binary.LittleEndian.Uint16(src[2:])
+ r2 := binary.LittleEndian.Uint16(src[4:])
+ r3 := binary.LittleEndian.Uint16(src[6:])
+
+ var j int
+
+ for j <= 16 {
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = bits.RotateLeft16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = bits.RotateLeft16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = bits.RotateLeft16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = bits.RotateLeft16(r3, 5)
+ j++
+
+ }
+
+ r0 = r0 + c.k[r3&63]
+ r1 = r1 + c.k[r0&63]
+ r2 = r2 + c.k[r1&63]
+ r3 = r3 + c.k[r2&63]
+
+ for j <= 40 {
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = bits.RotateLeft16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = bits.RotateLeft16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = bits.RotateLeft16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = bits.RotateLeft16(r3, 5)
+ j++
+
+ }
+
+ r0 = r0 + c.k[r3&63]
+ r1 = r1 + c.k[r0&63]
+ r2 = r2 + c.k[r1&63]
+ r3 = r3 + c.k[r2&63]
+
+ for j <= 60 {
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = bits.RotateLeft16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = bits.RotateLeft16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = bits.RotateLeft16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = bits.RotateLeft16(r3, 5)
+ j++
+ }
+
+ binary.LittleEndian.PutUint16(dst[0:], r0)
+ binary.LittleEndian.PutUint16(dst[2:], r1)
+ binary.LittleEndian.PutUint16(dst[4:], r2)
+ binary.LittleEndian.PutUint16(dst[6:], r3)
+}
+
+func (c *rc2Cipher) Decrypt(dst, src []byte) {
+
+ r0 := binary.LittleEndian.Uint16(src[0:])
+ r1 := binary.LittleEndian.Uint16(src[2:])
+ r2 := binary.LittleEndian.Uint16(src[4:])
+ r3 := binary.LittleEndian.Uint16(src[6:])
+
+ j := 63
+
+ for j >= 44 {
+ // unmix r3
+ r3 = bits.RotateLeft16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = bits.RotateLeft16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = bits.RotateLeft16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = bits.RotateLeft16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+ }
+
+ r3 = r3 - c.k[r2&63]
+ r2 = r2 - c.k[r1&63]
+ r1 = r1 - c.k[r0&63]
+ r0 = r0 - c.k[r3&63]
+
+ for j >= 20 {
+ // unmix r3
+ r3 = bits.RotateLeft16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = bits.RotateLeft16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = bits.RotateLeft16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = bits.RotateLeft16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+
+ }
+
+ r3 = r3 - c.k[r2&63]
+ r2 = r2 - c.k[r1&63]
+ r1 = r1 - c.k[r0&63]
+ r0 = r0 - c.k[r3&63]
+
+ for j >= 0 {
+ // unmix r3
+ r3 = bits.RotateLeft16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = bits.RotateLeft16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = bits.RotateLeft16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = bits.RotateLeft16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+
+ }
+
+ binary.LittleEndian.PutUint16(dst[0:], r0)
+ binary.LittleEndian.PutUint16(dst[2:], r1)
+ binary.LittleEndian.PutUint16(dst[4:], r2)
+ binary.LittleEndian.PutUint16(dst[6:], r3)
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/mac.go b/vendor/golang.org/x/crypto/pkcs12/mac.go
new file mode 100644
index 000000000..5f38aa7de
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/mac.go
@@ -0,0 +1,45 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+)
+
+type macData struct {
+ Mac digestInfo
+ MacSalt []byte
+ Iterations int `asn1:"optional,default:1"`
+}
+
+// from PKCS#7:
+type digestInfo struct {
+ Algorithm pkix.AlgorithmIdentifier
+ Digest []byte
+}
+
+var (
+ oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
+)
+
+func verifyMac(macData *macData, message, password []byte) error {
+ if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
+ return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
+ }
+
+ key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
+
+ mac := hmac.New(sha1.New, key)
+ mac.Write(message)
+ expectedMAC := mac.Sum(nil)
+
+ if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
+ return ErrIncorrectPassword
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pbkdf.go b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go
new file mode 100644
index 000000000..5c419d41e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go
@@ -0,0 +1,170 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "math/big"
+)
+
+var (
+ one = big.NewInt(1)
+)
+
+// sha1Sum returns the SHA-1 hash of in.
+func sha1Sum(in []byte) []byte {
+ sum := sha1.Sum(in)
+ return sum[:]
+}
+
+// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
+// repeats of pattern.
+func fillWithRepeats(pattern []byte, v int) []byte {
+ if len(pattern) == 0 {
+ return nil
+ }
+ outputLen := v * ((len(pattern) + v - 1) / v)
+ return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
+}
+
+func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
+ // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
+
+ // Let H be a hash function built around a compression function f:
+
+ // Z_2^u x Z_2^v -> Z_2^u
+
+ // (that is, H has a chaining variable and output of length u bits, and
+ // the message input to the compression function of H is v bits). The
+ // values for u and v are as follows:
+
+ // HASH FUNCTION VALUE u VALUE v
+ // MD2, MD5 128 512
+ // SHA-1 160 512
+ // SHA-224 224 512
+ // SHA-256 256 512
+ // SHA-384 384 1024
+ // SHA-512 512 1024
+ // SHA-512/224 224 1024
+ // SHA-512/256 256 1024
+
+ // Furthermore, let r be the iteration count.
+
+ // We assume here that u and v are both multiples of 8, as are the
+ // lengths of the password and salt strings (which we denote by p and s,
+ // respectively) and the number n of pseudorandom bits required. In
+ // addition, u and v are of course non-zero.
+
+ // For information on security considerations for MD5 [19], see [25] and
+ // [1], and on those for MD2, see [18].
+
+ // The following procedure can be used to produce pseudorandom bits for
+ // a particular "purpose" that is identified by a byte called "ID".
+ // This standard specifies 3 different values for the ID byte:
+
+ // 1. If ID=1, then the pseudorandom bits being produced are to be used
+ // as key material for performing encryption or decryption.
+
+ // 2. If ID=2, then the pseudorandom bits being produced are to be used
+ // as an IV (Initial Value) for encryption or decryption.
+
+ // 3. If ID=3, then the pseudorandom bits being produced are to be used
+ // as an integrity key for MACing.
+
+ // 1. Construct a string, D (the "diversifier"), by concatenating v/8
+ // copies of ID.
+ var D []byte
+ for i := 0; i < v; i++ {
+ D = append(D, ID)
+ }
+
+ // 2. Concatenate copies of the salt together to create a string S of
+ // length v(ceiling(s/v)) bits (the final copy of the salt may be
+ // truncated to create S). Note that if the salt is the empty
+ // string, then so is S.
+
+ S := fillWithRepeats(salt, v)
+
+ // 3. Concatenate copies of the password together to create a string P
+ // of length v(ceiling(p/v)) bits (the final copy of the password
+ // may be truncated to create P). Note that if the password is the
+ // empty string, then so is P.
+
+ P := fillWithRepeats(password, v)
+
+ // 4. Set I=S||P to be the concatenation of S and P.
+ I := append(S, P...)
+
+ // 5. Set c=ceiling(n/u).
+ c := (size + u - 1) / u
+
+ // 6. For i=1, 2, ..., c, do the following:
+ A := make([]byte, c*20)
+ var IjBuf []byte
+ for i := 0; i < c; i++ {
+ // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
+ // H(H(H(... H(D||I))))
+ Ai := hash(append(D, I...))
+ for j := 1; j < r; j++ {
+ Ai = hash(Ai)
+ }
+ copy(A[i*20:], Ai[:])
+
+ if i < c-1 { // skip on last iteration
+ // B. Concatenate copies of Ai to create a string B of length v
+ // bits (the final copy of Ai may be truncated to create B).
+ var B []byte
+ for len(B) < v {
+ B = append(B, Ai[:]...)
+ }
+ B = B[:v]
+
+ // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
+ // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
+ // setting I_j=(I_j+B+1) mod 2^v for each j.
+ {
+ Bbi := new(big.Int).SetBytes(B)
+ Ij := new(big.Int)
+
+ for j := 0; j < len(I)/v; j++ {
+ Ij.SetBytes(I[j*v : (j+1)*v])
+ Ij.Add(Ij, Bbi)
+ Ij.Add(Ij, one)
+ Ijb := Ij.Bytes()
+ // We expect Ijb to be exactly v bytes,
+ // if it is longer or shorter we must
+ // adjust it accordingly.
+ if len(Ijb) > v {
+ Ijb = Ijb[len(Ijb)-v:]
+ }
+ if len(Ijb) < v {
+ if IjBuf == nil {
+ IjBuf = make([]byte, v)
+ }
+ bytesShort := v - len(Ijb)
+ for i := 0; i < bytesShort; i++ {
+ IjBuf[i] = 0
+ }
+ copy(IjBuf[bytesShort:], Ijb)
+ Ijb = IjBuf
+ }
+ copy(I[j*v:(j+1)*v], Ijb)
+ }
+ }
+ }
+ }
+ // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
+ // bit string, A.
+
+ // 8. Use the first n bits of A as the output of this entire process.
+ return A[:size]
+
+ // If the above process is being used to generate a DES key, the process
+ // should be used to create 64 random bits, and the key's parity bits
+ // should be set after the 64 bits have been produced. Similar concerns
+ // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
+ // similar keys with parity bits "built into them".
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pkcs12.go b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go
new file mode 100644
index 000000000..374d9facf
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go
@@ -0,0 +1,364 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkcs12 implements some of PKCS#12.
+//
+// This implementation is distilled from [RFC 7292] and referenced documents.
+// It is intended for decoding P12/PFX-stored certificates and keys for use
+// with the crypto/tls package.
+//
+// The pkcs12 package is [frozen] and is not accepting new features.
+// If it's missing functionality you need, consider an alternative like
+// software.sslmate.com/src/go-pkcs12.
+//
+// [RFC 7292]: https://datatracker.ietf.org/doc/html/rfc7292
+// [frozen]: https://go.dev/wiki/Frozen
+package pkcs12
+
+import (
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/hex"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
+ oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
+
+ oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
+ oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
+ oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
+
+ errUnknownAttributeOID = errors.New("pkcs12: unknown attribute OID")
+)
+
+type pfxPdu struct {
+ Version int
+ AuthSafe contentInfo
+ MacData macData `asn1:"optional"`
+}
+
+type contentInfo struct {
+ ContentType asn1.ObjectIdentifier
+ Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
+}
+
+type encryptedData struct {
+ Version int
+ EncryptedContentInfo encryptedContentInfo
+}
+
+type encryptedContentInfo struct {
+ ContentType asn1.ObjectIdentifier
+ ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
+ EncryptedContent []byte `asn1:"tag:0,optional"`
+}
+
+func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
+ return i.ContentEncryptionAlgorithm
+}
+
+func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
+
+type safeBag struct {
+ Id asn1.ObjectIdentifier
+ Value asn1.RawValue `asn1:"tag:0,explicit"`
+ Attributes []pkcs12Attribute `asn1:"set,optional"`
+}
+
+type pkcs12Attribute struct {
+ Id asn1.ObjectIdentifier
+ Value asn1.RawValue `asn1:"set"`
+}
+
+type encryptedPrivateKeyInfo struct {
+ AlgorithmIdentifier pkix.AlgorithmIdentifier
+ EncryptedData []byte
+}
+
+func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
+ return i.AlgorithmIdentifier
+}
+
+func (i encryptedPrivateKeyInfo) Data() []byte {
+ return i.EncryptedData
+}
+
+// PEM block types
+const (
+ certificateType = "CERTIFICATE"
+ privateKeyType = "PRIVATE KEY"
+)
+
+// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
+// trailing data after unmarshaling.
+func unmarshal(in []byte, out interface{}) error {
+ trailing, err := asn1.Unmarshal(in, out)
+ if err != nil {
+ return err
+ }
+ if len(trailing) != 0 {
+ return errors.New("pkcs12: trailing data found")
+ }
+ return nil
+}
+
+// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
+// Unknown attributes are discarded.
+//
+// Note that although the returned PEM blocks for private keys have type
+// "PRIVATE KEY", the bytes are not encoded according to PKCS #8, but according
+// to PKCS #1 for RSA keys and SEC 1 for ECDSA keys.
+func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
+ encodedPassword, err := bmpString(password)
+ if err != nil {
+ return nil, ErrIncorrectPassword
+ }
+
+ bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+
+ if err != nil {
+ return nil, err
+ }
+
+ blocks := make([]*pem.Block, 0, len(bags))
+ for _, bag := range bags {
+ block, err := convertBag(&bag, encodedPassword)
+ if err != nil {
+ return nil, err
+ }
+ blocks = append(blocks, block)
+ }
+
+ return blocks, nil
+}
+
+func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
+ block := &pem.Block{
+ Headers: make(map[string]string),
+ }
+
+ for _, attribute := range bag.Attributes {
+ k, v, err := convertAttribute(&attribute)
+ if err == errUnknownAttributeOID {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ block.Headers[k] = v
+ }
+
+ switch {
+ case bag.Id.Equal(oidCertBag):
+ block.Type = certificateType
+ certsData, err := decodeCertBag(bag.Value.Bytes)
+ if err != nil {
+ return nil, err
+ }
+ block.Bytes = certsData
+ case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+ block.Type = privateKeyType
+
+ key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
+ if err != nil {
+ return nil, err
+ }
+
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ block.Bytes = x509.MarshalPKCS1PrivateKey(key)
+ case *ecdsa.PrivateKey:
+ block.Bytes, err = x509.MarshalECPrivateKey(key)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
+ }
+ default:
+ return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
+ }
+ return block, nil
+}
+
+func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
+ isString := false
+
+ switch {
+ case attribute.Id.Equal(oidFriendlyName):
+ key = "friendlyName"
+ isString = true
+ case attribute.Id.Equal(oidLocalKeyID):
+ key = "localKeyId"
+ case attribute.Id.Equal(oidMicrosoftCSPName):
+ // This key is chosen to match OpenSSL.
+ key = "Microsoft CSP Name"
+ isString = true
+ default:
+ return "", "", errUnknownAttributeOID
+ }
+
+ if isString {
+ if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
+ return "", "", err
+ }
+ if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
+ return "", "", err
+ }
+ } else {
+ var id []byte
+ if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
+ return "", "", err
+ }
+ value = hex.EncodeToString(id)
+ }
+
+ return key, value, nil
+}
+
+// Decode extracts a certificate and private key from pfxData. This function
+// assumes that there is only one certificate and only one private key in the
+// pfxData; if there are more use ToPEM instead.
+func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
+ encodedPassword, err := bmpString(password)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if len(bags) != 2 {
+ err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
+ return
+ }
+
+ for _, bag := range bags {
+ switch {
+ case bag.Id.Equal(oidCertBag):
+ if certificate != nil {
+ err = errors.New("pkcs12: expected exactly one certificate bag")
+ }
+
+ certsData, err := decodeCertBag(bag.Value.Bytes)
+ if err != nil {
+ return nil, nil, err
+ }
+ certs, err := x509.ParseCertificates(certsData)
+ if err != nil {
+ return nil, nil, err
+ }
+ if len(certs) != 1 {
+ err = errors.New("pkcs12: expected exactly one certificate in the certBag")
+ return nil, nil, err
+ }
+ certificate = certs[0]
+
+ case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+ if privateKey != nil {
+ err = errors.New("pkcs12: expected exactly one key bag")
+ return nil, nil, err
+ }
+
+ if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
+ return nil, nil, err
+ }
+ }
+ }
+
+ if certificate == nil {
+ return nil, nil, errors.New("pkcs12: certificate missing")
+ }
+ if privateKey == nil {
+ return nil, nil, errors.New("pkcs12: private key missing")
+ }
+
+ return
+}
+
+func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
+ pfx := new(pfxPdu)
+ if err := unmarshal(p12Data, pfx); err != nil {
+ return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
+ }
+
+ if pfx.Version != 3 {
+ return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
+ }
+
+ if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
+ return nil, nil, NotImplementedError("only password-protected PFX is implemented")
+ }
+
+ // unmarshal the explicit bytes in the content for type 'data'
+ if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
+ return nil, nil, err
+ }
+
+ if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
+ return nil, nil, errors.New("pkcs12: no MAC in data")
+ }
+
+ if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
+ if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
+ // some implementations use an empty byte array
+ // for the empty string password try one more
+ // time with empty-empty password
+ password = nil
+ err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ var authenticatedSafe []contentInfo
+ if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
+ return nil, nil, err
+ }
+
+ if len(authenticatedSafe) != 2 {
+ return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
+ }
+
+ for _, ci := range authenticatedSafe {
+ var data []byte
+
+ switch {
+ case ci.ContentType.Equal(oidDataContentType):
+ if err := unmarshal(ci.Content.Bytes, &data); err != nil {
+ return nil, nil, err
+ }
+ case ci.ContentType.Equal(oidEncryptedDataContentType):
+ var encryptedData encryptedData
+ if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
+ return nil, nil, err
+ }
+ if encryptedData.Version != 0 {
+ return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
+ }
+ if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
+ return nil, nil, err
+ }
+ default:
+ return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
+ }
+
+ var safeContents []safeBag
+ if err := unmarshal(data, &safeContents); err != nil {
+ return nil, nil, err
+ }
+ bags = append(bags, safeContents...)
+ }
+
+ return bags, password, nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/safebags.go b/vendor/golang.org/x/crypto/pkcs12/safebags.go
new file mode 100644
index 000000000..def1f7b98
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/safebags.go
@@ -0,0 +1,57 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "crypto/x509"
+ "encoding/asn1"
+ "errors"
+)
+
+var (
+ // see https://tools.ietf.org/html/rfc7292#appendix-D
+ oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
+ oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
+ oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
+)
+
+type certBag struct {
+ Id asn1.ObjectIdentifier
+ Data []byte `asn1:"tag:0,explicit"`
+}
+
+func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
+ pkinfo := new(encryptedPrivateKeyInfo)
+ if err = unmarshal(asn1Data, pkinfo); err != nil {
+ return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
+ }
+
+ pkData, err := pbDecrypt(pkinfo, password)
+ if err != nil {
+ return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
+ }
+
+ ret := new(asn1.RawValue)
+ if err = unmarshal(pkData, ret); err != nil {
+ return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
+ }
+
+ if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
+ return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
+ }
+
+ return privateKey, nil
+}
+
+func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
+ bag := new(certBag)
+ if err := unmarshal(asn1Data, bag); err != nil {
+ return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
+ }
+ if !bag.Id.Equal(oidCertTypeX509Certificate) {
+ return nil, NotImplementedError("only X509 certificates are supported")
+ }
+ return bag.Data, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 76c360b23..55d9ae48c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,3 +1,61 @@
+# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0
+## explicit; go 1.23.0
+github.com/Azure/azure-sdk-for-go/sdk/azcore
+github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource
+github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy
+github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime
+github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/fake
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op
+github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared
+github.com/Azure/azure-sdk-for-go/sdk/azcore/log
+github.com/Azure/azure-sdk-for-go/sdk/azcore/policy
+github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime
+github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming
+github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing
+# github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
+## explicit; go 1.23.0
+github.com/Azure/azure-sdk-for-go/sdk/azidentity
+github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal
+# github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2
+## explicit; go 1.23.0
+github.com/Azure/azure-sdk-for-go/sdk/internal/diag
+github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo
+github.com/Azure/azure-sdk-for-go/sdk/internal/exported
+github.com/Azure/azure-sdk-for-go/sdk/internal/log
+github.com/Azure/azure-sdk-for-go/sdk/internal/poller
+github.com/Azure/azure-sdk-for-go/sdk/internal/temporal
+github.com/Azure/azure-sdk-for-go/sdk/internal/uuid
+# github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0
+## explicit; go 1.18
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/exported
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/json/types/time
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/local
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/comm
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/internal/grant
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/wstrust/defs
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/options
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/shared
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/version
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/managedidentity
+github.com/AzureAD/microsoft-authentication-library-for-go/apps/public
# github.com/beorn7/perks v1.0.1
## explicit; go 1.11
github.com/beorn7/perks/quantile
@@ -48,6 +106,9 @@ github.com/gobwas/glob/syntax/ast
github.com/gobwas/glob/syntax/lexer
github.com/gobwas/glob/util/runes
github.com/gobwas/glob/util/strings
+# github.com/golang-jwt/jwt/v5 v5.3.0
+## explicit; go 1.21
+github.com/golang-jwt/jwt/v5
# github.com/golang/protobuf v1.5.4
## explicit; go 1.17
github.com/golang/protobuf/ptypes/empty
@@ -97,6 +158,10 @@ github.com/json-iterator/go
## explicit; go 1.22.0
github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1beta1
github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1
+# github.com/kylelemons/godebug v1.1.0
+## explicit; go 1.11
+github.com/kylelemons/godebug/diff
+github.com/kylelemons/godebug/pretty
# github.com/mailru/easyjson v0.9.0
## explicit; go 1.20
github.com/mailru/easyjson/buffer
@@ -163,6 +228,9 @@ github.com/openshift/hive/apis/scheme
github.com/openshift/hypershift/api/hypershift/v1beta1
github.com/openshift/hypershift/api/ibmcapi
github.com/openshift/hypershift/api/util/ipnet
+# github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
+## explicit; go 1.14
+github.com/pkg/browser
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
@@ -251,6 +319,10 @@ go.yaml.in/yaml/v2
# go.yaml.in/yaml/v3 v3.0.4
## explicit; go 1.16
go.yaml.in/yaml/v3
+# golang.org/x/crypto v0.49.0
+## explicit; go 1.25.0
+golang.org/x/crypto/pkcs12
+golang.org/x/crypto/pkcs12/internal/rc2
# golang.org/x/net v0.52.0
## explicit; go 1.25.0
golang.org/x/net/html