Skip to content

Commit cf03d0b

Browse files
authored
Added SAMLProviderConfigs() API for iterating for configurations (#281)
1 parent 754ef55 commit cf03d0b

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

auth/provider_config.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ import (
2020
"fmt"
2121
"net/http"
2222
"net/url"
23+
"strconv"
2324
"strings"
2425

2526
"firebase.google.com/go/internal"
27+
"google.golang.org/api/iterator"
2628
)
2729

2830
const (
2931
providerConfigEndpoint = "https://identitytoolkit.googleapis.com/v2beta1"
3032

33+
maxConfigs = 100
34+
3135
idpEntityIDKey = "idpConfig.idpEntityId"
3236
ssoURLKey = "idpConfig.ssoUrl"
3337
signRequestKey = "idpConfig.signRequest"
@@ -337,6 +341,65 @@ func (config *SAMLProviderConfigToUpdate) buildRequest() (nestedMap, error) {
337341
return config.params, nil
338342
}
339343

344+
// SAMLProviderConfigIterator is an iterator over SAML provider configurations.
345+
type SAMLProviderConfigIterator struct {
346+
client *providerConfigClient
347+
ctx context.Context
348+
nextFunc func() error
349+
pageInfo *iterator.PageInfo
350+
configs []*SAMLProviderConfig
351+
}
352+
353+
// PageInfo supports pagination.
354+
func (it *SAMLProviderConfigIterator) PageInfo() *iterator.PageInfo {
355+
return it.pageInfo
356+
}
357+
358+
// Next returns the next SAMLProviderConfig. The error value of [iterator.Done] is
359+
// returned if there are no more results. Once Next returns [iterator.Done], all
360+
// subsequent calls will return [iterator.Done].
361+
func (it *SAMLProviderConfigIterator) Next() (*SAMLProviderConfig, error) {
362+
if err := it.nextFunc(); err != nil {
363+
return nil, err
364+
}
365+
366+
config := it.configs[0]
367+
it.configs = it.configs[1:]
368+
return config, nil
369+
}
370+
371+
func (it *SAMLProviderConfigIterator) fetch(pageSize int, pageToken string) (string, error) {
372+
params := map[string]string{
373+
"pageSize": strconv.Itoa(pageSize),
374+
}
375+
if pageToken != "" {
376+
params["pageToken"] = pageToken
377+
}
378+
379+
req := &internal.Request{
380+
Method: http.MethodGet,
381+
URL: "/inboundSamlConfigs",
382+
Opts: []internal.HTTPOption{
383+
internal.WithQueryParams(params),
384+
},
385+
}
386+
387+
var result struct {
388+
Configs []samlProviderConfigDAO `json:"inboundSamlConfigs"`
389+
NextPageToken string `json:"nextPageToken"`
390+
}
391+
if _, err := it.client.makeRequest(it.ctx, req, &result); err != nil {
392+
return "", err
393+
}
394+
395+
for _, config := range result.Configs {
396+
it.configs = append(it.configs, config.toSAMLProviderConfig())
397+
}
398+
399+
it.pageInfo.Token = result.NextPageToken
400+
return result.NextPageToken, nil
401+
}
402+
340403
type providerConfigClient struct {
341404
endpoint string
342405
projectID string
@@ -453,6 +516,24 @@ func (c *providerConfigClient) DeleteSAMLProviderConfig(ctx context.Context, id
453516
return err
454517
}
455518

519+
// SAMLProviderConfigs returns an iterator over SAML provider configurations.
520+
//
521+
// If nextPageToken is empty, the iterator will start at the beginning. Otherwise,
522+
// iterator starts after the token.
523+
func (c *providerConfigClient) SAMLProviderConfigs(ctx context.Context, nextPageToken string) *SAMLProviderConfigIterator {
524+
it := &SAMLProviderConfigIterator{
525+
ctx: ctx,
526+
client: c,
527+
}
528+
it.pageInfo, it.nextFunc = iterator.NewPageInfo(
529+
it.fetch,
530+
func() int { return len(it.configs) },
531+
func() interface{} { b := it.configs; it.configs = nil; return b })
532+
it.pageInfo.MaxSize = maxConfigs
533+
it.pageInfo.Token = nextPageToken
534+
return it
535+
}
536+
456537
func (c *providerConfigClient) makeRequest(ctx context.Context, req *internal.Request, v interface{}) (*internal.Response, error) {
457538
if c.projectID == "" {
458539
return nil, errors.New("project id not available")

auth/provider_config_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"sort"
2424
"strings"
2525
"testing"
26+
27+
"google.golang.org/api/iterator"
2628
)
2729

2830
const samlConfigResponse = `{
@@ -624,6 +626,78 @@ func TestDeleteSAMLProviderConfigError(t *testing.T) {
624626
}
625627
}
626628

629+
func TestSAMLProviderConfigs(t *testing.T) {
630+
template := `{
631+
"inboundSamlConfigs": [
632+
%s,
633+
%s,
634+
%s
635+
],
636+
"nextPageToken": ""
637+
}`
638+
response := fmt.Sprintf(template, samlConfigResponse, samlConfigResponse, samlConfigResponse)
639+
s := echoServer([]byte(response), t)
640+
defer s.Close()
641+
642+
want := []*SAMLProviderConfig{
643+
samlProviderConfig,
644+
samlProviderConfig,
645+
samlProviderConfig,
646+
}
647+
648+
testIterator := func(iter *SAMLProviderConfigIterator, token string, req string) {
649+
count := 0
650+
for i := 0; i < len(want); i++ {
651+
config, err := iter.Next()
652+
if err == iterator.Done {
653+
break
654+
}
655+
if err != nil {
656+
t.Fatal(err)
657+
}
658+
if !reflect.DeepEqual(config, want[i]) {
659+
t.Errorf("SAMLProviderConfigs(%q) = %#v; want = %#v", token, config, want[i])
660+
}
661+
count++
662+
}
663+
if count != len(want) {
664+
t.Errorf("SAMLProviderConfigs(%q) = %d; want = %d", token, count, len(want))
665+
}
666+
if _, err := iter.Next(); err != iterator.Done {
667+
t.Errorf("SAMLProviderConfigs(%q) = %v, want = %v", token, err, iterator.Done)
668+
}
669+
670+
// Check the query string of the last HTTP request made.
671+
gotReq := s.Req[len(s.Req)-1].URL.Query().Encode()
672+
if gotReq != req {
673+
t.Errorf("SAMLProviderConfigs(%q) = %q, want = %v", token, gotReq, req)
674+
}
675+
}
676+
677+
client := s.Client.pcc
678+
testIterator(
679+
client.SAMLProviderConfigs(context.Background(), ""),
680+
"",
681+
"pageSize=100")
682+
testIterator(
683+
client.SAMLProviderConfigs(context.Background(), "pageToken"),
684+
"pageToken",
685+
"pageSize=100&pageToken=pageToken")
686+
}
687+
688+
func TestSAMLProviderConfigsError(t *testing.T) {
689+
s := echoServer([]byte("{}"), t)
690+
defer s.Close()
691+
s.Status = http.StatusInternalServerError
692+
693+
client := s.Client.pcc
694+
it := client.SAMLProviderConfigs(context.Background(), "")
695+
config, err := it.Next()
696+
if config != nil || err == nil || !IsUnknown(err) {
697+
t.Errorf("SAMLProviderConfigs() = (%v, %v); want = (nil, %q)", config, err, "unknown-error")
698+
}
699+
}
700+
627701
func TestSAMLProviderConfigNoProjectID(t *testing.T) {
628702
client := &providerConfigClient{}
629703
want := "project id not available"

0 commit comments

Comments
 (0)