zitadel/internal/idp/providers/oauth/session.go
Stefan Benz 15fd3045e0
feat: add SAML as identity provider (#6454)
* feat: first implementation for saml sp

* fix: add command side instance and org for saml provider

* fix: add query side instance and org for saml provider

* fix: request handling in event and retrieval of finished intent

* fix: add review changes and integration tests

* fix: add integration tests for saml idp

* fix: correct unit tests with review changes

* fix: add saml session unit test

* fix: add saml session unit test

* fix: add saml session unit test

* fix: changes from review

* fix: changes from review

* fix: proto build error

* fix: proto build error

* fix: proto build error

* fix: proto require metadata oneof

* fix: login with saml provider

* fix: integration test for saml assertion

* lint client.go

* fix json tag

* fix: linting

* fix import

* fix: linting

* fix saml idp query

* fix: linting

* lint: try all issues

* revert linting config

* fix: add regenerate endpoints

* fix: translations

* fix mk.yaml

* ignore acs path for user agent cookie

* fix: add AuthFromProvider test for saml

* fix: integration test for saml retrieve information

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
2023-09-29 11:26:14 +02:00

64 lines
1.6 KiB
Go

package oauth
import (
"context"
"errors"
"net/http"
"github.com/zitadel/oidc/v2/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v2/pkg/http"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/zitadel/internal/idp"
)
var ErrCodeMissing = errors.New("no auth code provided")
var _ idp.Session = (*Session)(nil)
// Session is the [idp.Session] implementation for the OAuth2.0 provider.
type Session struct {
AuthURL string
Code string
Tokens *oidc.Tokens[*oidc.IDTokenClaims]
Provider *Provider
}
// GetAuth implements the [idp.Session] interface.
func (s *Session) GetAuth(ctx context.Context) (string, bool) {
return idp.Redirect(s.AuthURL)
}
// FetchUser implements the [idp.Session] interface.
// It will execute an OAuth 2.0 code exchange if needed to retrieve the access token,
// call the specified userEndpoint and map the received information into an [idp.User].
func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) {
if s.Tokens == nil {
if err = s.authorize(ctx); err != nil {
return nil, err
}
}
req, err := http.NewRequest("GET", s.Provider.userEndpoint, nil)
if err != nil {
return nil, err
}
req.Header.Set("authorization", s.Tokens.TokenType+" "+s.Tokens.AccessToken)
mapper := s.Provider.userMapper()
if err := httphelper.HttpRequest(s.Provider.RelyingParty.HttpClient(), req, &mapper); err != nil {
return nil, err
}
return mapper, nil
}
func (s *Session) authorize(ctx context.Context) (err error) {
if s.Code == "" {
return ErrCodeMissing
}
s.Tokens, err = rp.CodeExchange[*oidc.IDTokenClaims](ctx, s.Code, s.Provider.RelyingParty)
if err != nil {
return err
}
return nil
}