mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 11:34:26 +00:00
164 lines
5.9 KiB
Go
164 lines
5.9 KiB
Go
|
package integration
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/zitadel/oidc/v2/pkg/client/rp"
|
||
|
"github.com/zitadel/oidc/v2/pkg/oidc"
|
||
|
|
||
|
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||
|
oidc_internal "github.com/zitadel/zitadel/internal/api/oidc"
|
||
|
"github.com/zitadel/zitadel/internal/command"
|
||
|
"github.com/zitadel/zitadel/pkg/grpc/app"
|
||
|
"github.com/zitadel/zitadel/pkg/grpc/management"
|
||
|
)
|
||
|
|
||
|
func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI string) (*management.AddOIDCAppResponse, error) {
|
||
|
project, err := s.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||
|
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
|
||
|
ProjectId: project.GetId(),
|
||
|
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
|
||
|
RedirectUris: []string{redirectURI},
|
||
|
ResponseTypes: []app.OIDCResponseType{app.OIDCResponseType_OIDC_RESPONSE_TYPE_CODE},
|
||
|
GrantTypes: []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE, app.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN},
|
||
|
AppType: app.OIDCAppType_OIDC_APP_TYPE_NATIVE,
|
||
|
AuthMethodType: app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE,
|
||
|
PostLogoutRedirectUris: nil,
|
||
|
Version: app.OIDCVersion_OIDC_VERSION_1_0,
|
||
|
DevMode: false,
|
||
|
AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT,
|
||
|
AccessTokenRoleAssertion: false,
|
||
|
IdTokenRoleAssertion: false,
|
||
|
IdTokenUserinfoAssertion: false,
|
||
|
ClockSkew: nil,
|
||
|
AdditionalOrigins: nil,
|
||
|
SkipNativeAppSuccessPage: false,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (s *Tester) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI string) (*management.AddOIDCAppResponse, error) {
|
||
|
project, err := s.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{
|
||
|
Name: fmt.Sprintf("project-%d", time.Now().UnixNano()),
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
|
||
|
ProjectId: project.GetId(),
|
||
|
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
|
||
|
RedirectUris: []string{redirectURI},
|
||
|
ResponseTypes: []app.OIDCResponseType{app.OIDCResponseType_OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN},
|
||
|
GrantTypes: []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_IMPLICIT},
|
||
|
AppType: app.OIDCAppType_OIDC_APP_TYPE_USER_AGENT,
|
||
|
AuthMethodType: app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE,
|
||
|
PostLogoutRedirectUris: nil,
|
||
|
Version: app.OIDCVersion_OIDC_VERSION_1_0,
|
||
|
DevMode: true,
|
||
|
AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT,
|
||
|
AccessTokenRoleAssertion: false,
|
||
|
IdTokenRoleAssertion: false,
|
||
|
IdTokenUserinfoAssertion: false,
|
||
|
ClockSkew: nil,
|
||
|
AdditionalOrigins: nil,
|
||
|
SkipNativeAppSuccessPage: false,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (s *Tester) CreateOIDCAuthRequest(clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
||
|
provider, err := s.CreateRelyingParty(clientID, redirectURI, scope...)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
codeVerifier := "codeVerifier"
|
||
|
codeChallenge := oidc.NewSHACodeChallenge(codeVerifier)
|
||
|
authURL := rp.AuthURL("state", provider, rp.WithCodeChallenge(codeChallenge))
|
||
|
|
||
|
loc, err := CheckRedirect(authURL, map[string]string{oidc_internal.LoginClientHeader: loginClient})
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
prefixWithHost := provider.Issuer() + s.Config.OIDC.DefaultLoginURLV2
|
||
|
if !strings.HasPrefix(loc.String(), prefixWithHost) {
|
||
|
return "", fmt.Errorf("login location has not prefix %s, but is %s", prefixWithHost, loc.String())
|
||
|
}
|
||
|
return strings.TrimPrefix(loc.String(), prefixWithHost), nil
|
||
|
}
|
||
|
|
||
|
func (s *Tester) CreateOIDCAuthRequestImplicit(clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
||
|
provider, err := s.CreateRelyingParty(clientID, redirectURI, scope...)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
authURL := rp.AuthURL("state", provider)
|
||
|
|
||
|
// implicit is not natively supported so let's just overwrite the response type
|
||
|
parsed, _ := url.Parse(authURL)
|
||
|
queries := parsed.Query()
|
||
|
queries.Set("response_type", string(oidc.ResponseTypeIDToken))
|
||
|
parsed.RawQuery = queries.Encode()
|
||
|
authURL = parsed.String()
|
||
|
|
||
|
loc, err := CheckRedirect(authURL, map[string]string{oidc_internal.LoginClientHeader: loginClient})
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
prefixWithHost := provider.Issuer() + s.Config.OIDC.DefaultLoginURLV2
|
||
|
if !strings.HasPrefix(loc.String(), prefixWithHost) {
|
||
|
return "", fmt.Errorf("login location has not prefix %s, but is %s", prefixWithHost, loc.String())
|
||
|
}
|
||
|
return strings.TrimPrefix(loc.String(), prefixWithHost), nil
|
||
|
}
|
||
|
|
||
|
func (s *Tester) CreateRelyingParty(clientID, redirectURI string, scope ...string) (rp.RelyingParty, error) {
|
||
|
issuer := http_util.BuildHTTP(s.Config.ExternalDomain, s.Config.Port, s.Config.ExternalSecure)
|
||
|
if len(scope) == 0 {
|
||
|
scope = []string{oidc.ScopeOpenID}
|
||
|
}
|
||
|
return rp.NewRelyingPartyOIDC(issuer, clientID, "", redirectURI, scope)
|
||
|
}
|
||
|
|
||
|
func CheckRedirect(url string, headers map[string]string) (*url.URL, error) {
|
||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for key, value := range headers {
|
||
|
req.Header.Set(key, value)
|
||
|
}
|
||
|
|
||
|
client := &http.Client{
|
||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||
|
return http.ErrUseLastResponse
|
||
|
},
|
||
|
}
|
||
|
resp, err := client.Do(req)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
return resp.Location()
|
||
|
}
|
||
|
|
||
|
func (s *Tester) CreateSession(ctx context.Context, userID string) (string, string, error) {
|
||
|
session, err := s.Commands.CreateSession(ctx, []command.SessionCommand{command.CheckUser(userID)}, "domain.tld", nil)
|
||
|
if err != nil {
|
||
|
return "", "", err
|
||
|
}
|
||
|
return session.ID, session.NewToken, nil
|
||
|
}
|