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