diff --git a/identity_provider.go b/identity_provider.go index 4c7282ae..ffde2a0d 100644 --- a/identity_provider.go +++ b/identity_provider.go @@ -875,12 +875,23 @@ func (req *IdpAuthnRequest) MakeAssertionEl() error { return nil } -// WriteResponse writes the `Response` to the http.ResponseWriter. If -// `Response` is not already set, it calls MakeResponse to produce it. -func (req *IdpAuthnRequest) WriteResponse(w http.ResponseWriter) error { +// IdpAuthnRequestForm contans HTML form information to be submitted to the +// SAML HTTP POST binding ACS. +type IdpAuthnRequestForm struct { + URL string + SAMLResponse string + RelayState string +} + +// PostBinding creates the HTTP POST form information for this +// `IdpAuthnRequest`. If `Response` is not already set, it calls MakeResponse +// to produce it. +func (req *IdpAuthnRequest) PostBinding() (IdpAuthnRequestForm, error) { + var form IdpAuthnRequestForm + if req.ResponseEl == nil { if err := req.MakeResponse(); err != nil { - return err + return form, err } } @@ -888,45 +899,48 @@ func (req *IdpAuthnRequest) WriteResponse(w http.ResponseWriter) error { doc.SetRoot(req.ResponseEl) responseBuf, err := doc.WriteToBytes() if err != nil { - return err + return form, err } - // the only supported binding is the HTTP-POST binding - switch req.ACSEndpoint.Binding { - case HTTPPostBinding: - tmpl := template.Must(template.New("saml-post-form").Parse(`` + - `
` + - `` + - `` + - `` + - `
` + - `` + - `` + - ``)) - data := struct { - URL string - SAMLResponse string - RelayState string - }{ - URL: req.ACSEndpoint.Location, - SAMLResponse: base64.StdEncoding.EncodeToString(responseBuf), - RelayState: req.RelayState, - } - - buf := bytes.NewBuffer(nil) - if err := tmpl.Execute(buf, data); err != nil { - return err - } - if _, err := io.Copy(w, buf); err != nil { - return err - } - return nil - - default: - return fmt.Errorf("%s: unsupported binding %s", + if req.ACSEndpoint.Binding != HTTPPostBinding { + return form, fmt.Errorf("%s: unsupported binding %s", req.ServiceProviderMetadata.EntityID, req.ACSEndpoint.Binding) } + + form.URL = req.ACSEndpoint.Location + form.SAMLResponse = base64.StdEncoding.EncodeToString(responseBuf) + form.RelayState = req.RelayState + + return form, nil +} + +// WriteResponse writes the `Response` to the http.ResponseWriter. If +// `Response` is not already set, it calls MakeResponse to produce it. +func (req *IdpAuthnRequest) WriteResponse(w http.ResponseWriter) error { + form, err := req.PostBinding() + if err != nil { + return err + } + + tmpl := template.Must(template.New("saml-post-form").Parse(`` + + `
` + + `` + + `` + + `` + + `
` + + `` + + `` + + ``)) + + buf := bytes.NewBuffer(nil) + if err := tmpl.Execute(buf, form); err != nil { + return err + } + if _, err := io.Copy(w, buf); err != nil { + return err + } + return nil } // getSPEncryptionCert returns the certificate which we can use to encrypt things