diff --git a/README.md b/README.md index f2cb3d72..04bb7e93 100644 --- a/README.md +++ b/README.md @@ -222,9 +222,9 @@ type GoCloak interface { SetRestyClient(restyClient *resty.Client) GetToken(ctx context.Context, realm string, options TokenOptions) (*JWT, error) - GetRequestingPartyToken(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*JWT, error) - GetRequestingPartyPermissions(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) - GetRequestingPartyPermissionDecision(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) + GetRequestingPartyToken(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*JWT, error) + GetRequestingPartyPermissions(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) + GetRequestingPartyPermissionDecision(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) Login(ctx context.Context, clientID, clientSecret, realm, username, password string) (*JWT, error) LoginOtp(ctx context.Context, clientID, clientSecret, realm, username, password, totp string) (*JWT, error) diff --git a/client.go b/client.go index 71c0319f..b73c9322 100644 --- a/client.go +++ b/client.go @@ -84,8 +84,16 @@ func (client *gocloak) getRequestWithBasicAuth(ctx context.Context, clientID, cl return req } -func (client *gocloak) getRequestingParty(ctx context.Context, token string, realm string, options RequestingPartyTokenOptions, res interface{}) (*resty.Response, error) { - return client.getRequestWithBearerAuth(ctx, token). +func (client *gocloak) getRequestingParty(ctx context.Context, token string, clientID string, clientSecret string, realm string, options RequestingPartyTokenOptions, res interface{}) (*resty.Response, error) { + var req *resty.Request + + if !NilOrEmpty(&token) { + req = client.getRequestWithBearerAuth(ctx, token) + } else { + req = client.getRequestWithBasicAuth(ctx, clientID, clientSecret) + } + + return req. SetFormData(options.FormData()). SetFormDataFromValues(url.Values{"permission": PStringSlice(options.Permissions)}). SetResult(&res). @@ -453,12 +461,12 @@ func (client *gocloak) GetToken(ctx context.Context, realm string, options Token } // GetRequestingPartyToken returns a requesting party token with permissions granted by the server -func (client *gocloak) GetRequestingPartyToken(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*JWT, error) { +func (client *gocloak) GetRequestingPartyToken(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*JWT, error) { const errMessage = "could not get requesting party token" var res JWT - resp, err := client.getRequestingParty(ctx, token, realm, options, &res) + resp, err := client.getRequestingParty(ctx, token, clientID, clientSecret, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err @@ -468,14 +476,14 @@ func (client *gocloak) GetRequestingPartyToken(ctx context.Context, token, realm } // GetRequestingPartyPermissions returns a requesting party permissions granted by the server -func (client *gocloak) GetRequestingPartyPermissions(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) { +func (client *gocloak) GetRequestingPartyPermissions(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) { const errMessage = "could not get requesting party token" var res []RequestingPartyPermission options.ResponseMode = StringP("permissions") - resp, err := client.getRequestingParty(ctx, token, realm, options, &res) + resp, err := client.getRequestingParty(ctx, token, clientID, clientSecret, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err @@ -485,14 +493,14 @@ func (client *gocloak) GetRequestingPartyPermissions(ctx context.Context, token, } // GetRequestingPartyPermissionDecision returns a requesting party permission decision granted by the server -func (client *gocloak) GetRequestingPartyPermissionDecision(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) { +func (client *gocloak) GetRequestingPartyPermissionDecision(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) { const errMessage = "could not get requesting party token" var res RequestingPartyPermissionDecision options.ResponseMode = StringP("decision") - resp, err := client.getRequestingParty(ctx, token, realm, options, &res) + resp, err := client.getRequestingParty(ctx, token, clientID, clientSecret, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err diff --git a/client_test.go b/client_test.go index a2222798..0b83e6de 100644 --- a/client_test.go +++ b/client_test.go @@ -675,6 +675,8 @@ func Test_RetrospectRequestingPartyToken(t *testing.T) { rpt, err := client.GetRequestingPartyToken( context.Background(), token.AccessToken, + "", + "", cfg.GoCloak.Realm, gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), @@ -688,6 +690,8 @@ func Test_RetrospectRequestingPartyToken(t *testing.T) { rpt, err = client.GetRequestingPartyToken( context.Background(), token.AccessToken, + "", + "", cfg.GoCloak.Realm, gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), @@ -732,6 +736,8 @@ func Test_GetRequestingPartyPermissions(t *testing.T) { context.Background(), token.AccessToken, "", + "", + "", gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), Permissions: &[]string{ @@ -744,6 +750,8 @@ func Test_GetRequestingPartyPermissions(t *testing.T) { rpp, err = client.GetRequestingPartyPermissions( context.Background(), token.AccessToken, + "", + "", cfg.GoCloak.Realm, gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), @@ -760,6 +768,58 @@ func Test_GetRequestingPartyPermissions(t *testing.T) { require.Equal(t, "Default Resource", *permissions[0].ResourceName, "GetRequestingPartyPermissions failed") } +func Test_GetRequestingPartyPermissionsBasicAuth(t *testing.T) { + // t.Parallel() + cfg := GetConfig(t) + client := NewClientWithDebug(t) + SetUpTestUser(t, client) + token, err := client.Login( + context.Background(), + cfg.GoCloak.ClientID, + cfg.GoCloak.ClientSecret, + cfg.GoCloak.Realm, + cfg.GoCloak.UserName, + cfg.GoCloak.Password) + require.NoError(t, err, "login failed") + + rpp, err := client.GetRequestingPartyPermissions( + context.Background(), + "", + cfg.GoCloak.ClientID, + cfg.GoCloak.ClientSecret, + "", + gocloak.RequestingPartyTokenOptions{ + Audience: gocloak.StringP(cfg.GoCloak.ClientID), + SubjectToken: gocloak.StringP(token.AccessToken), + Permissions: &[]string{ + "Default Resource", + }, + }) + require.Error(t, err, "GetRequestingPartyPermissions failed") + require.Nil(t, rpp) + + rpp, err = client.GetRequestingPartyPermissions( + context.Background(), + "", + cfg.GoCloak.ClientID, + cfg.GoCloak.ClientSecret, + cfg.GoCloak.Realm, + gocloak.RequestingPartyTokenOptions{ + Audience: gocloak.StringP(cfg.GoCloak.ClientID), + SubjectToken: gocloak.StringP(token.AccessToken), + Permissions: &[]string{ + "Default Resource", + }, + }) + require.NoError(t, err, "GetRequestingPartyPermissions failed") + require.NotNil(t, rpp) + + t.Log(rpp) + permissions := *rpp + require.Len(t, permissions, 1, "GetRequestingPartyPermissions failed") + require.Equal(t, "Default Resource", *permissions[0].ResourceName, "GetRequestingPartyPermissions failed") +} + func Test_GetRequestingPartyPermissionDecision(t *testing.T) { // t.Parallel() cfg := GetConfig(t) @@ -778,6 +838,8 @@ func Test_GetRequestingPartyPermissionDecision(t *testing.T) { context.Background(), token.AccessToken, "", + "", + "", gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), }) @@ -787,6 +849,8 @@ func Test_GetRequestingPartyPermissionDecision(t *testing.T) { dec, err = client.GetRequestingPartyPermissionDecision( context.Background(), token.AccessToken, + "", + "", cfg.GoCloak.Realm, gocloak.RequestingPartyTokenOptions{ Audience: gocloak.StringP(cfg.GoCloak.ClientID), @@ -1064,6 +1128,8 @@ func Test_GetRequestingPartyToken(t *testing.T) { rpt, err := client.GetRequestingPartyToken( context.Background(), newToken.AccessToken, + "", + "", cfg.GoCloak.Realm, gocloak.RequestingPartyTokenOptions{ Audience: &cfg.GoCloak.ClientID, diff --git a/gocloak.go b/gocloak.go index d09bdf9f..cf328802 100644 --- a/gocloak.go +++ b/gocloak.go @@ -18,11 +18,11 @@ type GoCloak interface { // GetToken returns a token GetToken(ctx context.Context, realm string, options TokenOptions) (*JWT, error) // GetRequestingPartyToken returns a requesting party token with permissions granted by the server - GetRequestingPartyToken(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*JWT, error) + GetRequestingPartyToken(ctx context.Context, token, clientID, cliientSecret, realm string, options RequestingPartyTokenOptions) (*JWT, error) // GetRequestingPartyPermissions returns a permissions granted by the server to requesting party - GetRequestingPartyPermissions(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) + GetRequestingPartyPermissions(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) // GetRequestingPartyPermissionDecision returns a permission decision granted by the server to requesting party - GetRequestingPartyPermissionDecision(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) + GetRequestingPartyPermissionDecision(ctx context.Context, token, clientID, clientSecret, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) // Login sends a request to the token endpoint using user and client credentials Login(ctx context.Context, clientID, clientSecret, realm, username, password string) (*JWT, error) // LoginOtp performs a login with user credentials and otp token