mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-15 20:38:00 +00:00
f680dd934d
* chore: rename package errors to zerrors * rename package errors to gerrors * fix error related linting issues * fix zitadel error assertion * fix gosimple linting issues * fix deprecated linting issues * resolve gci linting issues * fix import structure --------- Co-authored-by: Elio Bischof <elio@zitadel.com>
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
package saml
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/crewjam/saml"
|
|
"github.com/crewjam/saml/samlsp"
|
|
|
|
"github.com/zitadel/zitadel/internal/idp"
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
var _ idp.Session = (*Session)(nil)
|
|
|
|
// Session is the [idp.Session] implementation for the SAML provider.
|
|
type Session struct {
|
|
ServiceProvider *samlsp.Middleware
|
|
state string
|
|
|
|
RequestID string
|
|
Request *http.Request
|
|
|
|
Assertion *saml.Assertion
|
|
}
|
|
|
|
// GetAuth implements the [idp.Session] interface.
|
|
func (s *Session) GetAuth(ctx context.Context) (string, bool) {
|
|
url, _ := url.Parse(s.state)
|
|
resp := NewTempResponseWriter()
|
|
|
|
request := &http.Request{
|
|
URL: url,
|
|
}
|
|
s.ServiceProvider.HandleStartAuthFlow(
|
|
resp,
|
|
request.WithContext(ctx),
|
|
)
|
|
|
|
if location := resp.Header().Get("Location"); location != "" {
|
|
return idp.Redirect(location)
|
|
}
|
|
return idp.Form(resp.content.String())
|
|
}
|
|
|
|
// FetchUser implements the [idp.Session] interface.
|
|
func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) {
|
|
if s.RequestID == "" || s.Request == nil {
|
|
return nil, zerrors.ThrowInvalidArgument(nil, "SAML-d09hy0wkex", "Errors.Intent.ResponseInvalid")
|
|
}
|
|
|
|
s.Assertion, err = s.ServiceProvider.ServiceProvider.ParseResponse(s.Request, []string{s.RequestID})
|
|
if err != nil {
|
|
return nil, zerrors.ThrowInvalidArgument(err, "SAML-nuo0vphhh9", "Errors.Intent.ResponseInvalid")
|
|
}
|
|
|
|
userMapper := NewUser()
|
|
userMapper.SetID(s.Assertion.Subject.NameID)
|
|
for _, statement := range s.Assertion.AttributeStatements {
|
|
for _, attribute := range statement.Attributes {
|
|
values := make([]string, len(attribute.Values))
|
|
for i := range attribute.Values {
|
|
values[i] = attribute.Values[i].Value
|
|
}
|
|
userMapper.Attributes[attribute.Name] = values
|
|
}
|
|
}
|
|
return userMapper, nil
|
|
}
|
|
|
|
type TempResponseWriter struct {
|
|
header http.Header
|
|
content *bytes.Buffer
|
|
}
|
|
|
|
func (w *TempResponseWriter) Header() http.Header {
|
|
return w.header
|
|
}
|
|
|
|
func (w *TempResponseWriter) Write(content []byte) (int, error) {
|
|
return w.content.Write(content)
|
|
}
|
|
|
|
func (w *TempResponseWriter) WriteHeader(statusCode int) {}
|
|
|
|
func NewTempResponseWriter() *TempResponseWriter {
|
|
return &TempResponseWriter{
|
|
header: map[string][]string{},
|
|
content: bytes.NewBuffer([]byte{}),
|
|
}
|
|
}
|