...

Source file src/github.com/ory/fosite/client_authentication_jwks_strategy.go

Documentation: github.com/ory/fosite

     1  /*
     2   * Copyright © 2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @Copyright 	2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   *
    20   */
    21  
    22  package fosite
    23  
    24  import (
    25  	"encoding/json"
    26  	"net/http"
    27  	"sync"
    28  
    29  	"github.com/ory/x/errorsx"
    30  
    31  	jose "gopkg.in/square/go-jose.v2"
    32  )
    33  
    34  // JWKSFetcherStrategy is a strategy which pulls (optionally caches) JSON Web Key Sets from a location,
    35  // typically a client's jwks_uri.
    36  type JWKSFetcherStrategy interface {
    37  	// Resolve returns the JSON Web Key Set, or an error if something went wrong. The forceRefresh, if true, forces
    38  	// the strategy to fetch the keys from the remote. If forceRefresh is false, the strategy may use a caching strategy
    39  	// to fetch the key.
    40  	Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error)
    41  }
    42  
    43  type DefaultJWKSFetcherStrategy struct {
    44  	client *http.Client
    45  	keys   map[string]jose.JSONWebKeySet
    46  	sync.Mutex
    47  }
    48  
    49  func NewDefaultJWKSFetcherStrategy() JWKSFetcherStrategy {
    50  	return &DefaultJWKSFetcherStrategy{
    51  		keys:   make(map[string]jose.JSONWebKeySet),
    52  		client: http.DefaultClient,
    53  	}
    54  }
    55  
    56  func (s *DefaultJWKSFetcherStrategy) Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error) {
    57  	s.Lock()
    58  	defer s.Unlock()
    59  
    60  	keys, ok := s.keys[location]
    61  	if !ok || forceRefresh {
    62  		response, err := s.client.Get(location)
    63  		if err != nil {
    64  			return nil, errorsx.WithStack(ErrServerError.WithHintf("Unable to fetch JSON Web Keys from location '%s'. Check for typos or other network issues.", location).WithWrap(err).WithDebug(err.Error()))
    65  		}
    66  		defer response.Body.Close()
    67  
    68  		if response.StatusCode < 200 || response.StatusCode >= 400 {
    69  			return nil, errorsx.WithStack(ErrServerError.WithHintf("Expected successful status code in range of 200 - 399 from location '%s' but received code %d.", location, response.StatusCode))
    70  		}
    71  
    72  		var set jose.JSONWebKeySet
    73  		if err := json.NewDecoder(response.Body).Decode(&set); err != nil {
    74  			return nil, errorsx.WithStack(ErrServerError.WithHintf("Unable to decode JSON Web Keys from location '%s'. Please check for typos and if the URL returns valid JSON.", location).WithWrap(err).WithDebug(err.Error()))
    75  		}
    76  
    77  		s.keys[location] = set
    78  		return &set, nil
    79  	}
    80  
    81  	return &keys, nil
    82  }
    83  

View as plain text