github.com/crewjam/saml@v0.4.14/samlidp/shortcut.go (about) 1 package samlidp 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/zenazn/goji/web" 9 ) 10 11 // Shortcut represents an IDP-initiated SAML flow. When a user 12 // navigates to /login/:shortcut it initiates the login flow 13 // to the specified service provider with the specified 14 // RelayState. 15 type Shortcut struct { 16 // The name of the shortcut. 17 Name string `json:"name"` 18 19 // The entity ID of the service provider to use for this shortcut, i.e. 20 // https://someapp.example.com/saml/metadata. 21 ServiceProviderID string `json:"service_provider"` 22 23 // If specified then the relay state is the fixed string provided 24 RelayState *string `json:"relay_state,omitempty"` 25 26 // If true then the URL suffix is used as the relayState. So for example, a user 27 // requesting https://idp.example.com/login/myservice/foo will get redirected 28 // to the myservice endpoint with a RelayState of "foo". 29 URISuffixAsRelayState bool `json:"url_suffix_as_relay_state,omitempty"` 30 } 31 32 // HandleListShortcuts handles the `GET /shortcuts/` request and responds with a JSON formatted list 33 // of shortcut names. 34 func (s *Server) HandleListShortcuts(_ web.C, w http.ResponseWriter, _ *http.Request) { 35 shortcuts, err := s.Store.List("/shortcuts/") 36 if err != nil { 37 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 38 return 39 } 40 41 err = json.NewEncoder(w).Encode(struct { 42 Shortcuts []string `json:"shortcuts"` 43 }{Shortcuts: shortcuts}) 44 if err != nil { 45 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 46 return 47 } 48 } 49 50 // HandleGetShortcut handles the `GET /shortcuts/:id` request and responds with the shortcut 51 // object in JSON format. 52 func (s *Server) HandleGetShortcut(c web.C, w http.ResponseWriter, _ *http.Request) { 53 shortcut := Shortcut{} 54 err := s.Store.Get(fmt.Sprintf("/shortcuts/%s", c.URLParams["id"]), &shortcut) 55 if err != nil { 56 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 57 return 58 } 59 if err := json.NewEncoder(w).Encode(shortcut); err != nil { 60 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 61 return 62 } 63 } 64 65 // HandlePutShortcut handles the `PUT /shortcuts/:id` request. It accepts a JSON formatted 66 // shortcut object in the request body and stores it. 67 func (s *Server) HandlePutShortcut(c web.C, w http.ResponseWriter, r *http.Request) { 68 shortcut := Shortcut{} 69 if err := json.NewDecoder(r.Body).Decode(&shortcut); err != nil { 70 http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) 71 return 72 } 73 shortcut.Name = c.URLParams["id"] 74 75 err := s.Store.Put(fmt.Sprintf("/shortcuts/%s", c.URLParams["id"]), &shortcut) 76 if err != nil { 77 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 78 return 79 } 80 w.WriteHeader(http.StatusNoContent) 81 } 82 83 // HandleDeleteShortcut handles the `DELETE /shortcuts/:id` request. 84 func (s *Server) HandleDeleteShortcut(c web.C, w http.ResponseWriter, _ *http.Request) { 85 err := s.Store.Delete(fmt.Sprintf("/shortcuts/%s", c.URLParams["id"])) 86 if err != nil { 87 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 88 return 89 } 90 w.WriteHeader(http.StatusNoContent) 91 } 92 93 // HandleIDPInitiated handles a request for an IDP initiated login flow. It looks up 94 // the specified shortcut, generates the appropriate SAML assertion and redirects the 95 // user via the HTTP-POST binding to the service providers ACS URL. 96 func (s *Server) HandleIDPInitiated(c web.C, w http.ResponseWriter, r *http.Request) { 97 shortcutName := c.URLParams["shortcut"] 98 shortcut := Shortcut{} 99 if err := s.Store.Get(fmt.Sprintf("/shortcuts/%s", shortcutName), &shortcut); err != nil { 100 s.logger.Printf("ERROR: %s", err) 101 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 102 return 103 } 104 105 relayState := "" 106 switch { 107 case shortcut.RelayState != nil: 108 relayState = *shortcut.RelayState 109 case shortcut.URISuffixAsRelayState: 110 relayState = c.URLParams["*"] 111 } 112 113 s.idpConfigMu.RLock() 114 defer s.idpConfigMu.RUnlock() 115 s.IDP.ServeIDPInitiated(w, r, shortcut.ServiceProviderID, relayState) 116 }