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 }