github.com/crewjam/saml@v0.4.14/samlidp/service.go (about)

     1  package samlidp
     2  
     3  import (
     4  	"encoding/json"
     5  	"encoding/xml"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  
    10  	"github.com/zenazn/goji/web"
    11  
    12  	"github.com/crewjam/saml"
    13  )
    14  
    15  // Service represents a configured SP for whom this IDP provides authentication services.
    16  type Service struct {
    17  	// Name is the name of the service provider
    18  	Name string
    19  
    20  	// Metdata is the XML metadata of the service provider.
    21  	Metadata saml.EntityDescriptor
    22  }
    23  
    24  // GetServiceProvider returns the Service Provider metadata for the
    25  // service provider ID, which is typically the service provider's
    26  // metadata URL. If an appropriate service provider cannot be found then
    27  // the returned error must be os.ErrNotExist.
    28  func (s *Server) GetServiceProvider(_ *http.Request, serviceProviderID string) (*saml.EntityDescriptor, error) {
    29  	s.idpConfigMu.RLock()
    30  	defer s.idpConfigMu.RUnlock()
    31  	rv, ok := s.serviceProviders[serviceProviderID]
    32  	if !ok {
    33  		return nil, os.ErrNotExist
    34  	}
    35  	return rv, nil
    36  }
    37  
    38  // HandleListServices handles the `GET /services/` request and responds with a JSON formatted list
    39  // of service names.
    40  func (s *Server) HandleListServices(_ web.C, w http.ResponseWriter, _ *http.Request) {
    41  	services, err := s.Store.List("/services/")
    42  	if err != nil {
    43  		s.logger.Printf("ERROR: %s", err)
    44  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    45  		return
    46  	}
    47  
    48  	err = json.NewEncoder(w).Encode(struct {
    49  		Services []string `json:"services"`
    50  	}{Services: services})
    51  	if err != nil {
    52  		s.logger.Printf("ERROR: %s", err)
    53  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    54  	}
    55  }
    56  
    57  // HandleGetService handles the `GET /services/:id` request and responds with the service
    58  // metadata in XML format.
    59  func (s *Server) HandleGetService(c web.C, w http.ResponseWriter, _ *http.Request) {
    60  	service := Service{}
    61  	err := s.Store.Get(fmt.Sprintf("/services/%s", c.URLParams["id"]), &service)
    62  	if err != nil {
    63  		s.logger.Printf("ERROR: %s", err)
    64  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    65  		return
    66  	}
    67  	err = xml.NewEncoder(w).Encode(service.Metadata)
    68  	if err != nil {
    69  		s.logger.Printf("ERROR: %s", err)
    70  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    71  	}
    72  }
    73  
    74  // HandlePutService handles the `PUT /shortcuts/:id` request. It accepts the XML-formatted
    75  // service metadata in the request body and stores it.
    76  func (s *Server) HandlePutService(c web.C, w http.ResponseWriter, r *http.Request) {
    77  	service := Service{}
    78  
    79  	metadata, err := getSPMetadata(r.Body)
    80  	if err != nil {
    81  		s.logger.Printf("ERROR: %s", err)
    82  		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    83  		return
    84  	}
    85  
    86  	service.Metadata = *metadata
    87  
    88  	err = s.Store.Put(fmt.Sprintf("/services/%s", c.URLParams["id"]), &service)
    89  	if err != nil {
    90  		s.logger.Printf("ERROR: %s", err)
    91  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    92  		return
    93  	}
    94  
    95  	s.idpConfigMu.Lock()
    96  	s.serviceProviders[service.Metadata.EntityID] = &service.Metadata
    97  	s.idpConfigMu.Unlock()
    98  
    99  	w.WriteHeader(http.StatusNoContent)
   100  }
   101  
   102  // HandleDeleteService handles the `DELETE /services/:id` request.
   103  func (s *Server) HandleDeleteService(c web.C, w http.ResponseWriter, _ *http.Request) {
   104  	service := Service{}
   105  	err := s.Store.Get(fmt.Sprintf("/services/%s", c.URLParams["id"]), &service)
   106  	if err != nil {
   107  		s.logger.Printf("ERROR: %s", err)
   108  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
   109  		return
   110  	}
   111  
   112  	if err := s.Store.Delete(fmt.Sprintf("/services/%s", c.URLParams["id"])); err != nil {
   113  		s.logger.Printf("ERROR: %s", err)
   114  		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
   115  		return
   116  	}
   117  
   118  	s.idpConfigMu.Lock()
   119  	delete(s.serviceProviders, service.Metadata.EntityID)
   120  	s.idpConfigMu.Unlock()
   121  
   122  	w.WriteHeader(http.StatusNoContent)
   123  }
   124  
   125  // initializeServices reads all the stored services and initializes the underlying
   126  // identity provider to accept them.
   127  func (s *Server) initializeServices() error {
   128  	serviceNames, err := s.Store.List("/services/")
   129  	if err != nil {
   130  		return err
   131  	}
   132  	for _, serviceName := range serviceNames {
   133  		service := Service{}
   134  		if err := s.Store.Get(fmt.Sprintf("/services/%s", serviceName), &service); err != nil {
   135  			return err
   136  		}
   137  
   138  		s.idpConfigMu.Lock()
   139  		s.serviceProviders[service.Metadata.EntityID] = &service.Metadata
   140  		s.idpConfigMu.Unlock()
   141  	}
   142  	return nil
   143  }