Skip to content

Commit

Permalink
Add Go AzureIdentityCredentialAdapter, readme and test (#32)
Browse files Browse the repository at this point in the history
* add go etension

* add go model

* add go model

* change readme

* change code

* change code and readme

* change readme

* change according to comment

* refactor with base adapter

* remove comment code

* change according to comments

* change according to comments

* change readme

* change according to comments

* change according to comments

* change according to comments

* change package version

Co-authored-by: Zhanle Tu <v-zhanlt@microsoft.com>
  • Loading branch information
Luyunmt and tzhanl authored Sep 14, 2020
1 parent 2e124e7 commit 361e0c8
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 1 deletion.
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This repo is a place for us to share ideas and extensions to the Azure Identity
## Languages

We currently have included examples for [.NET](#.NET), [Java](#Java), [JavaScript/TypeScript](#TypeScript), and [Python](#Python). Please file an issue if you would like examples for other languages as well.
We currently have included examples for [.NET](#.NET), [Java](#Java), [JavaScript/TypeScript](#TypeScript), [Golang](#Golang), and [Python](#Python). Please file an issue if you would like examples for other languages as well.

## Usage

Expand Down Expand Up @@ -167,6 +167,43 @@ tsc azureIdentityCredentialAdapter.spec.ts --esModuleInterop

Once you have the `.env` file configured and js compiled, run the test simply calling `mocha azureIdentityCredentialAdapter.spec.js --timeout 10000`.

## Golang

### NewAzureIdentityCredentialAdapter

The `NewAzureIdentityCredentialAdapter` function allows you to use all the goodness of `azidentity` in the Azure Management libraries. You can use it in place of `Authorizer` when calling your Azure Management APIs.

To use this type, just import package github.com/jongio/azidext/go/azidext and using follow command to get package.

```
go get -u github.com/jongio/azidext/go/azidext
```

Use `NewAzureIdentityCredentialAdapter` in place of `Authorizer`:

```go
import "github.com/jongio/azidext/go/azidext"

groupsClient := resources.NewGroupsClient(subscriptionID)
a, err := NewDefaultAzureCredentialAdapter(nil)
if err != nil {
}
groupsClient.Authorizer = a
```

#### Testing NewAzureIdentityCredentialAdapter

This repository has a test that creates a resource group in a given subscription.

To run this test, ensure you have `.env` file created and accessible from the root of your repo. Your `.env` file should have the following properties set:

- AZURE_SUBSCRIPTION_ID
- AZURE_TENANT_ID
- AZURE_CLIENT_ID
- AZURE_CLIENT_SECRET

Once you have the `.env` file configured, run the test simply calling `go test`.

## Python

### AzureIdentityCredentialAdapter
Expand Down
94 changes: 94 additions & 0 deletions go/azidext/azure_identity_credential_adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package azidext

import (
"errors"
"net/http"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/go-autorest/autorest"
)

// NewAzureIdentityCredentialAdapter is used to adapt an azcore.Credential to an autorest.Authorizer
func NewAzureIdentityCredentialAdapter(credential azcore.Credential, options azcore.AuthenticationPolicyOptions) autorest.Authorizer {
policy := credential.AuthenticationPolicy(options)
return &policyAdapter{p: policy}
}

type policyAdapter struct {
p azcore.Policy
}

// WithAuthorization implements the autorest.Authorizer interface for type policyAdapter.
func (ca *policyAdapter) WithAuthorization() autorest.PrepareDecorator {
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
r, err := p.Prepare(r)
if err != nil {
return r, err
}
_, err = ca.p.Do(&azcore.Request{Request: r})
if errors.Is(err, azcore.ErrNoMorePolicies) {
return r, nil
}
var afe *azidentity.AuthenticationFailedError
if errors.As(err, &afe) {
err = &tokenRefreshError{
inner: afe,
}
}
return r, err
})
}
}

type tokenRefreshError struct {
inner error
}

func (t *tokenRefreshError) Error() string {
return t.inner.Error()
}

func (t *tokenRefreshError) Response() *http.Response {
return nil
}

func (t *tokenRefreshError) Unwrap() error {
return t.inner
}

// DefaultManagementScope is the default credential scope for Azure Resource Management.
const DefaultManagementScope = "https://management.azure.com//.default"

// DefaultAzureCredentialOptions contains credential and authentication policy options.
type DefaultAzureCredentialOptions struct {
// DefaultCredential contains configuration options passed to azidentity.NewDefaultAzureCredential().
// Set this to nil to accept the underlying default behavior.
DefaultCredential *azidentity.DefaultAzureCredentialOptions

// AuthenticationPolicy contains configuration options passed to the underlying authentication policy.
// Setting this to nil will use the DefaultManagementScope when acquiring a token.
AuthenticationPolicy *azcore.AuthenticationPolicyOptions
}

// NewDefaultAzureCredentialAdapter adapts azcore.NewDefaultAzureCredential to an autorest.Authorizer.
func NewDefaultAzureCredentialAdapter(options *DefaultAzureCredentialOptions) (autorest.Authorizer, error) {
if options == nil {
options = &DefaultAzureCredentialOptions{
AuthenticationPolicy: &azcore.AuthenticationPolicyOptions{
Options: azcore.TokenRequestOptions{
Scopes: []string{DefaultManagementScope},
},
},
}
}
chain, err := azidentity.NewDefaultAzureCredential(options.DefaultCredential)
if err != nil {
return nil, err
}
return NewAzureIdentityCredentialAdapter(chain, *options.AuthenticationPolicy), nil
}
45 changes: 45 additions & 0 deletions go/azidext/azure_identity_credential_adapter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package azidext

import (
"context"
"math/rand"
"os"
"strconv"
"testing"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/to"
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-05-01/resources"
"github.com/joho/godotenv"
)

func Test_CreateResouceGroup(t *testing.T) {
err := godotenv.Load("../../.env")
if err != nil {
t.Fatalf("Loading environment variable from .env fail, error: %v", err)
}
subscriptionID := os.Getenv("AZURE_SUBSCRIPTION_ID")
if subscriptionID == "" {
t.Fatalf("Missing environment variable AZURE_SUBSCRIPTION_ID")
}
groupsClient := resources.NewGroupsClient(subscriptionID)
a, err := NewDefaultAzureCredentialAdapter(nil)
if err != nil {
t.Fatalf("Create DefaultAzureIdentityTokenAapter fail, error: %v", err)
}
groupsClient.Authorizer = a
resourceGroupname := "azidextrg" + strconv.FormatInt(int64(rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000000)), 10)

_, err = groupsClient.CreateOrUpdate(
context.Background(),
resourceGroupname,
resources.Group{
Location: to.StringPtr("Central US"),
})
if err != nil {
t.Fatalf("Create ResourceGroup fail, error: %v", err)
}
}
14 changes: 14 additions & 0 deletions go/azidext/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module github.com/jongio/azidext/go/azidext

go 1.13

require (
github.com/Azure/azure-sdk-for-go v46.0.0+incompatible
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.10.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.2.0
github.com/Azure/azure-sdk-for-go/sdk/to v0.1.1
github.com/Azure/go-autorest/autorest v0.11.4
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect
github.com/joho/godotenv v1.3.0
)
51 changes: 51 additions & 0 deletions go/azidext/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
github.com/Azure/azure-sdk-for-go v46.0.0+incompatible h1:4qlEOCDcDQZTGczYGzbGYCdJfVpZLIs8AEo5+MoXBPw=
github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.10.0 h1:bicoLZMjsxg6LqSFRpLaAmVGqZtOS9hrCVi0KdqcCco=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.10.0/go.mod h1:R+GJZ0mj7yxXtTENNLTzwkwro5zWzrEiZOdpIiN7Ypc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.2.0 h1:0s/9rnsRwEwd6heP3N+iUv3xRgommZUvu9SJZkcECNI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.2.0/go.mod h1:/XqWZ+BVfDwHnN6x+Ns+VH2Le0x0Yhks6I2DHkIyGGo=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.2.1/go.mod h1:Q+TCQnSr+clUU0JU+xrHZ3slYCxw17AOFdvWFpQXjAY=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.2.2/go.mod h1:Q+TCQnSr+clUU0JU+xrHZ3slYCxw17AOFdvWFpQXjAY=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.3.0 h1:l7b+GcynB+tNmqq4yrQG2mMzp34gNu65CC5iGTKVlOA=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.3.0/go.mod h1:Q+TCQnSr+clUU0JU+xrHZ3slYCxw17AOFdvWFpQXjAY=
github.com/Azure/azure-sdk-for-go/sdk/to v0.1.1 h1:xfQtpQrdXC5By+/gOhE6rLRevCw17TLfjSWzkGkT58Y=
github.com/Azure/azure-sdk-for-go/sdk/to v0.1.1/go.mod h1:UL/d4lvWAzSJUuX+19uKdN0ktyjoOyQhgY+HWNgtIYI=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.4 h1:iWJqGEvip7mjibEqC/srXNdo+4wLEPiwlP/7dZLtoPc=
github.com/Azure/go-autorest/autorest v0.11.4/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
github.com/Azure/go-autorest/autorest/adal v0.9.0 h1:SigMbuFNuKgc1xcGhaeapbh+8fgsu+GxgDRFyg7f5lM=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
github.com/Azure/go-autorest/autorest/validation v0.3.0 h1:3I9AAI63HfcLtphd9g39ruUwRI+Ca+z/f36KHPFRUss=
github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

0 comments on commit 361e0c8

Please sign in to comment.