github.com/crewjam/saml@v0.4.14/samlidp/samlidp.go (about) 1 // Package samlidp a rudimentary SAML identity provider suitable for 2 // testing or as a starting point for a more complex service. 3 package samlidp 4 5 import ( 6 "crypto" 7 "crypto/x509" 8 "net/http" 9 "net/url" 10 "regexp" 11 "sync" 12 13 "github.com/zenazn/goji/web" 14 15 "github.com/crewjam/saml" 16 "github.com/crewjam/saml/logger" 17 ) 18 19 // Options represent the parameters to New() for creating a new IDP server 20 type Options struct { 21 URL url.URL 22 Key crypto.PrivateKey 23 Signer crypto.Signer 24 Logger logger.Interface 25 Certificate *x509.Certificate 26 Store Store 27 } 28 29 // Server represents an IDP server. The server provides the following URLs: 30 // 31 // /metadata - the SAML metadata 32 // /sso - the SAML endpoint to initiate an authentication flow 33 // /login - prompt for a username and password if no session established 34 // /login/:shortcut - kick off an IDP-initiated authentication flow 35 // /services - RESTful interface to Service objects 36 // /users - RESTful interface to User objects 37 // /sessions - RESTful interface to Session objects 38 // /shortcuts - RESTful interface to Shortcut objects 39 type Server struct { 40 http.Handler 41 idpConfigMu sync.RWMutex // protects calls into the IDP 42 logger logger.Interface 43 serviceProviders map[string]*saml.EntityDescriptor 44 IDP saml.IdentityProvider // the underlying IDP 45 Store Store // the data store 46 } 47 48 // New returns a new Server 49 func New(opts Options) (*Server, error) { 50 metadataURL := opts.URL 51 metadataURL.Path += "/metadata" 52 ssoURL := opts.URL 53 ssoURL.Path += "/sso" 54 logr := opts.Logger 55 if logr == nil { 56 logr = logger.DefaultLogger 57 } 58 59 s := &Server{ 60 serviceProviders: map[string]*saml.EntityDescriptor{}, 61 IDP: saml.IdentityProvider{ 62 Key: opts.Key, 63 Signer: opts.Signer, 64 Logger: logr, 65 Certificate: opts.Certificate, 66 MetadataURL: metadataURL, 67 SSOURL: ssoURL, 68 }, 69 logger: logr, 70 Store: opts.Store, 71 } 72 73 s.IDP.SessionProvider = s 74 s.IDP.ServiceProviderProvider = s 75 76 if err := s.initializeServices(); err != nil { 77 return nil, err 78 } 79 s.InitializeHTTP() 80 return s, nil 81 } 82 83 // InitializeHTTP sets up the HTTP handler for the server. (This function 84 // is called automatically for you by New, but you may need to call it 85 // yourself if you don't create the object using New.) 86 func (s *Server) InitializeHTTP() { 87 mux := web.New() 88 s.Handler = mux 89 90 mux.Get("/metadata", func(w http.ResponseWriter, r *http.Request) { 91 s.idpConfigMu.RLock() 92 defer s.idpConfigMu.RUnlock() 93 s.IDP.ServeMetadata(w, r) 94 }) 95 mux.Handle("/sso", func(w http.ResponseWriter, r *http.Request) { 96 s.idpConfigMu.RLock() 97 defer s.idpConfigMu.RUnlock() 98 s.IDP.ServeSSO(w, r) 99 }) 100 101 mux.Handle("/login", s.HandleLogin) 102 mux.Handle("/login/:shortcut", s.HandleIDPInitiated) 103 mux.Handle("/login/:shortcut/*", s.HandleIDPInitiated) 104 105 mux.Get("/services/", s.HandleListServices) 106 mux.Get("/services/:id", s.HandleGetService) 107 mux.Put("/services/:id", s.HandlePutService) 108 mux.Post("/services/:id", s.HandlePutService) 109 mux.Delete("/services/:id", s.HandleDeleteService) 110 111 mux.Get("/users/", s.HandleListUsers) 112 mux.Get("/users/:id", s.HandleGetUser) 113 mux.Put("/users/:id", s.HandlePutUser) 114 mux.Delete("/users/:id", s.HandleDeleteUser) 115 116 sessionPath := regexp.MustCompile("/sessions/(?P<id>.*)") 117 mux.Get("/sessions/", s.HandleListSessions) 118 mux.Get(sessionPath, s.HandleGetSession) 119 mux.Delete(sessionPath, s.HandleDeleteSession) 120 121 mux.Get("/shortcuts/", s.HandleListShortcuts) 122 mux.Get("/shortcuts/:id", s.HandleGetShortcut) 123 mux.Put("/shortcuts/:id", s.HandlePutShortcut) 124 mux.Delete("/shortcuts/:id", s.HandleDeleteShortcut) 125 }