Skip to content

Commit 2ccdfe2

Browse files
committed
add default identity provider as well
1 parent 5b21e16 commit 2ccdfe2

9 files changed

+299
-181
lines changed

authority_configuration.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package entraid
2+
3+
import "fmt"
4+
5+
const (
6+
// AuthorityTypeDefault is the default authority type.
7+
// This is used to specify the authority type when requesting a token.
8+
AuthorityTypeDefault = "default"
9+
// AuthorityTypeMultiTenant is the multi-tenant authority type.
10+
// This is used to specify the multi-tenant authority type when requesting a token.
11+
// This type of authority is used to authenticate the identity when requesting a token.
12+
AuthorityTypeMultiTenant = "multi-tenant"
13+
// AuthorityTypeCustom is the custom authority type.
14+
// This is used to specify the custom authority type when requesting a token.
15+
AuthorityTypeCustom = "custom"
16+
)
17+
18+
// AuthorityConfiguration represents the authority configuration for the identity provider.
19+
// It is used to configure the authority type and authority URL when requesting a token.
20+
type AuthorityConfiguration struct {
21+
// AuthorityType is the type of authority used to authenticate with the identity provider.
22+
// This can be either "default", "multi-tenant", or "custom".
23+
AuthorityType string
24+
25+
// Authority is the authority used to authenticate with the identity provider.
26+
// This is typically the URL of the identity provider.
27+
// For example, "https://login.microsoftonline.com/{tenantID}/v2.0"
28+
Authority string
29+
30+
// TenantID is the tenant ID of the identity provider.
31+
// This is used to identify the tenant when requesting a token.
32+
// This is typically the ID of the Azure Active Directory tenant.
33+
TenantID string
34+
}
35+
36+
// getAuthority returns the authority URL based on the authority type.
37+
// The authority type can be either "default", "multi-tenant", or "custom".
38+
func (a AuthorityConfiguration) getAuthority() (string, error) {
39+
if a.AuthorityType == "" {
40+
a.AuthorityType = AuthorityTypeDefault
41+
}
42+
43+
switch a.AuthorityType {
44+
case AuthorityTypeDefault:
45+
return "https://login.microsoftonline.com/common", nil
46+
case AuthorityTypeMultiTenant:
47+
if a.TenantID == "" {
48+
return "", fmt.Errorf("tenant ID is required when using multi-tenant authority type")
49+
}
50+
return fmt.Sprintf("https://login.microsoftonline.com/%s", a.TenantID), nil
51+
case AuthorityTypeCustom:
52+
if a.Authority == "" {
53+
return "", fmt.Errorf("authority is required when using custom authority type")
54+
}
55+
return a.Authority, nil
56+
default:
57+
return "", fmt.Errorf("invalid authority type: %s", a.AuthorityType)
58+
}
59+
}

azure_default_identity_provider.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package entraid
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
8+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
9+
)
10+
11+
// DefaultAzureIdentityProviderOptions represents the options for the DefaultAzureIdentityProvider.
12+
type DefaultAzureIdentityProviderOptions struct {
13+
// Scopes is the list of scopes used to request a token from the identity provider.
14+
AzureOptions *azidentity.DefaultAzureCredentialOptions
15+
Scopes []string
16+
}
17+
18+
type DefaultAzureIdentityProvider struct {
19+
options *azidentity.DefaultAzureCredentialOptions
20+
scopes []string
21+
}
22+
23+
// NewDefaultAzureIdentityProvider creates a new DefaultAzureIdentityProvider.
24+
func NewDefaultAzureIdentityProvider(opts DefaultAzureIdentityProviderOptions) (*DefaultAzureIdentityProvider, error) {
25+
if opts.Scopes == nil {
26+
opts.Scopes = []string{RedisScopeDefault}
27+
}
28+
29+
return &DefaultAzureIdentityProvider{options: opts.AzureOptions, scopes: opts.Scopes}, nil
30+
}
31+
32+
// RequestToken requests a token from the Azure Default Identity provider.
33+
// It returns the token, the expiration time, and an error if any.
34+
func (a *DefaultAzureIdentityProvider) RequestToken() (string, time.Time, error) {
35+
cred, err := azidentity.NewDefaultAzureCredential(a.options)
36+
if err != nil {
37+
return "", time.Time{}, err
38+
}
39+
40+
token, err := cred.GetToken(context.TODO(), policy.TokenRequestOptions{Scopes: a.scopes})
41+
if err != nil {
42+
return "", time.Time{}, err
43+
}
44+
45+
return token.Token, token.ExpiresOn.UTC(), nil
46+
}

confidential_identity_provider.go

Lines changed: 38 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,14 @@ package entraid
33
import (
44
"context"
55
"crypto"
6-
"errors"
6+
"crypto/x509"
77
"fmt"
8-
confidential "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
9-
)
8+
"time"
109

11-
import "crypto/x509"
12-
13-
const (
14-
// AuthorityTypeDefault is the default authority type.
15-
// This is used to specify the authority type when requesting a token.
16-
AuthorityTypeDefault = "default"
17-
// AuthorityTypeMultiTenant is the multi-tenant authority type.
18-
// This is used to specify the multi-tenant authority type when requesting a token.
19-
// This type of authority is used to authenticate the identity when requesting a token.
20-
AuthorityTypeMultiTenant = "multi-tenant"
21-
// AuthorityTypeCustom is the custom authority type.
22-
// This is used to specify the custom authority type when requesting a token.
23-
AuthorityTypeCustom = "custom"
10+
confidential "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
2411
)
2512

26-
type AuthorityConfiguration struct {
27-
// AuthorityType is the type of authority used to authenticate with the identity provider.
28-
// This can be either "default", "multi-tenant", or "custom".
29-
AuthorityType string
30-
31-
// Authority is the authority used to authenticate with the identity provider.
32-
// This is typically the URL of the identity provider.
33-
// For example, "https://login.microsoftonline.com/{tenantID}/v2.0"
34-
Authority string
35-
36-
// TenantID is the tenant ID of the identity provider.
37-
// This is used to identify the tenant when requesting a token.
38-
// This is typically the ID of the Azure Active Directory tenant.
39-
TenantID string
40-
}
41-
42-
func (a AuthorityConfiguration) GetAuthority() (string, error) {
43-
if a.AuthorityType == "" {
44-
a.AuthorityType = AuthorityTypeDefault
45-
}
46-
47-
switch a.AuthorityType {
48-
case AuthorityTypeDefault:
49-
return "https://login.microsoftonline.com/common", nil
50-
case AuthorityTypeMultiTenant:
51-
if a.TenantID == "" {
52-
return "", errors.New("tenant ID is required when using multi-tenant authority type")
53-
}
54-
return fmt.Sprintf("https://login.microsoftonline.com/%s", a.TenantID), nil
55-
case AuthorityTypeCustom:
56-
if a.Authority == "" {
57-
return "", errors.New("authority is required when using custom authority type")
58-
}
59-
return a.Authority, nil
60-
default:
61-
return "", errors.New("invalid authority type")
62-
}
63-
}
64-
65-
type ConfidentialIdentityProvider struct {
66-
// clientID is the client ID used to authenticate with the identity provider.
67-
clientID string
68-
69-
// credential is the credential used to authenticate with the identity provider.
70-
credential confidential.Credential
71-
72-
// scopes is the list of scopes used to request a token from the identity provider.
73-
scopes []string
74-
75-
// client confidential is the client used to request a token from the identity provider.
76-
client *confidential.Client
77-
}
78-
13+
// ConfidentialIdentityProviderOptions represents the options for the confidential identity provider.
7914
type ConfidentialIdentityProviderOptions struct {
8015
// ClientID is the client ID used to authenticate with the identity provider.
8116
ClientID string
@@ -99,21 +34,42 @@ type ConfidentialIdentityProviderOptions struct {
9934
Authority AuthorityConfiguration
10035
}
10136

37+
// ConfidentialIdentityProvider represents a confidential identity provider.
38+
type ConfidentialIdentityProvider struct {
39+
// clientID is the client ID used to authenticate with the identity provider.
40+
clientID string
41+
42+
// credential is the credential used to authenticate with the identity provider.
43+
credential confidential.Credential
44+
45+
// scopes is the list of scopes used to request a token from the identity provider.
46+
scopes []string
47+
48+
// client confidential is the client used to request a token from the identity provider.
49+
client *confidential.Client
50+
}
51+
52+
// NewConfidentialIdentityProvider creates a new confidential identity provider.
53+
// It is used to configure the identity provider when requesting a token.
54+
// It is used to specify the client ID, tenant ID, and scopes for the identity.
55+
// It is also used to specify the type of credentials used to authenticate with the identity provider.
56+
// The credentials can be either a client secret or a client certificate.
57+
// The authority is used to authenticate with the identity provider.
10258
func NewConfidentialIdentityProvider(opts ConfidentialIdentityProviderOptions) (*ConfidentialIdentityProvider, error) {
10359
var credential confidential.Credential
10460
var authority string
10561
var err error
10662

10763
if opts.ClientID == "" {
108-
return nil, errors.New("client ID is required")
64+
return nil, fmt.Errorf("client ID is required")
10965
}
11066

11167
if opts.CredentialsType != ClientSecretCredentialType && opts.CredentialsType != ClientCertificateCredentialType {
112-
return nil, errors.New("invalid credentials type")
68+
return nil, fmt.Errorf("invalid credentials type")
11369
}
11470

11571
// Get the authority from the authority configuration.
116-
authority, err = opts.Authority.GetAuthority()
72+
authority, err = opts.Authority.getAuthority()
11773
if err != nil {
11874
return nil, fmt.Errorf("failed to get authority: %w", err)
11975
}
@@ -122,7 +78,7 @@ func NewConfidentialIdentityProvider(opts ConfidentialIdentityProviderOptions) (
12278
case ClientSecretCredentialType:
12379
// ClientSecretCredentialType is the type of credentials that uses a client secret to authenticate.
12480
if opts.ClientSecret == "" {
125-
return nil, errors.New("client secret is required when using client secret credentials")
81+
return nil, fmt.Errorf("client secret is required when using client secret credentials")
12682
}
12783

12884
credential, err = confidential.NewCredFromSecret(opts.ClientSecret)
@@ -132,10 +88,10 @@ func NewConfidentialIdentityProvider(opts ConfidentialIdentityProviderOptions) (
13288
case ClientCertificateCredentialType:
13389
// ClientCertificateCredentialType is the type of credentials that uses a client certificate to authenticate.
13490
if opts.ClientCert == nil {
135-
return nil, errors.New("client certificate is required when using client certificate credentials")
91+
return nil, fmt.Errorf("client certificate is required when using client certificate credentials")
13692
}
13793
if opts.ClientPrivateKey == nil {
138-
return nil, errors.New("client private key is required when using client certificate credentials")
94+
return nil, fmt.Errorf("client private key is required when using client certificate credentials")
13995
}
14096
credential, err = confidential.NewCredFromCert(opts.ClientCert, opts.ClientPrivateKey)
14197
if err != nil {
@@ -160,15 +116,18 @@ func NewConfidentialIdentityProvider(opts ConfidentialIdentityProviderOptions) (
160116
}, nil
161117
}
162118

163-
func (c *ConfidentialIdentityProvider) RequestToken() (string, error) {
119+
// RequestToken requests a token from the identity provider.
120+
// It returns the token, the expiration time, and an error if any.
121+
// The token is used to authenticate the identity when requesting a token.
122+
func (c *ConfidentialIdentityProvider) RequestToken() (string, time.Time, error) {
164123
if c.client == nil {
165-
return "", errors.New("client is not initialized")
124+
return "", time.Time{}, fmt.Errorf("client is not initialized")
166125
}
167126

168127
result, err := c.client.AcquireTokenByCredential(context.TODO(), c.scopes)
169128
if err != nil {
170-
return "", fmt.Errorf("failed to acquire token: %w", err)
129+
return "", time.Time{}, fmt.Errorf("failed to acquire token: %w", err)
171130
}
172131

173-
return result.AccessToken, nil
132+
return result.AccessToken, result.ExpiresOn.UTC(), nil
174133
}

credentials_provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
"sync"
66

7-
"github.com/redis/go-redis/v9/auth"
7+
auth "github.com/redis/go-redis/v9/auth"
88
)
99

1010
// entraidCredentialsProvider implements the auth.StreamingCredentialsProvider interface.

go.mod

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ go 1.18
44

55
replace github.com/redis/go-redis/v9 => /Users/nedyalko.dyakov/go-redis/
66

7-
require github.com/redis/go-redis/v9 v9.7.1
7+
require (
8+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
9+
github.com/redis/go-redis/v9 v9.7.1
10+
)
811

9-
require github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1 // indirect
12+
require (
13+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
14+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
15+
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1
16+
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
17+
github.com/google/uuid v1.6.0 // indirect
18+
github.com/kylelemons/godebug v1.1.0 // indirect
19+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
20+
golang.org/x/crypto v0.33.0 // indirect
21+
golang.org/x/net v0.35.0 // indirect
22+
golang.org/x/sys v0.30.0 // indirect
23+
golang.org/x/text v0.22.0 // indirect
24+
)

go.sum

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
1+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
2+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
3+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
4+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
5+
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
6+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
7+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
8+
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
19
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1 h1:8BKxhZZLX/WosEeoCvWysmKUscfa9v8LIPEEU0JjE2o=
210
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
3-
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
4-
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
5-
github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
11+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
12+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
13+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
14+
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
15+
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
16+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
17+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
18+
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
19+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
20+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
21+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
22+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
23+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
24+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
25+
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
26+
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
27+
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
28+
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
29+
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
30+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
31+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
32+
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
33+
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
34+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)