OAuthアクセストークンを使ってMicrosoft Azureにアクセスする


# 概要

[Microsoft Azureを利用するデスクトップアプリのデバイス認証](http://qiita.com/jkawamoto/items/d6588faff0ee03b1be74)にて取得したアクセストークンを，
[Go から Microsoft Azure を利用する](http://qiita.com/jkawamoto/items/e0761cbe7a4c42305cc0)にて紹介した Swagger で生成したクライアントから利用する方法．
API によって微妙に関数の形が変わるため，生成されたソースコードを見ながらどこでトークンを渡せるのか調べる必要があるが，おおよそ次の二種類に分かれると思われる．


# メソッドが認証情報を受け取る場合

最も簡単なのは，認証情報を受け取るタイプのメソッドが生成された場合である．
例えば，次のようにして生成できる 2016-09-01 版の Resource API

```sh
$ swagger generate client -f https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-resources/resources/2016-09-01/swagger/resources.json -t resource
```

では，リソースグループの作成または更新を行う関数が次のように定義されている．

```go
func (a *Client) ResourceGroupsCreateOrUpdate(
	params *ResourceGroupsCreateOrUpdateParams,
	authInfo runtime.ClientAuthInfoWriter
) (*ResourceGroupsCreateOrUpdateOK, *ResourceGroupsCreateOrUpdateCreated, error)
```

この [runtime.ClientAuthInfoWriter](https://godoc.org/github.com/go-openapi/runtime#ClientAuthInfoWriter)型は，[go-openapi/runtime](https://github.com/go-openapi/runtime) ライブラリにて

```go
import 	"github.com/go-openapi/strfmt"

type ClientAuthInfoWriter interface {
    AuthenticateRequest(ClientRequest, strfmt.Registry) error
}
```

と定義されているのだが，[go-openapi/runtime/client](https://github.com/go-openapi/runtime/client) に OAuth アクセストークン (BearerToken) から ClientAuthInfoWriter を生成する [BearerToken](https://godoc.org/github.com/go-openapi/runtime/client#BearerToken) 関数が用意されている．

`token` にアクセストークンが入っているのであれば，

```go
authInfo = httptransport.BearerToken(token)
```

で良い．

なお，client という名のパッケージがたくさん出てくるため，go-openapi/runtime/client には httptransport という別名を与えることが多いらしい．

実際に，ResourceGroupsCreateOrUpdate を呼び出すコードは次のようになる．

```go
import (
	// Swagger で生成した resource の中にあるパッケージ群
	// （ディレクトリは生成した環境によって異なる）
	"github.com/jkawamoto/roadie/cloud/azure/resource/client"
	"github.com/jkawamoto/roadie/cloud/azure/resource/client/resource_groups"
	"github.com/jkawamoto/roadie/cloud/azure/resource/models"
	
	httptransport "github.com/go-openapi/runtime/client"
	"github.com/go-openapi/strfmt"
)

const (
	// 生成した API のバージョン
	ResourceAPIVersion = "2016-09-01"
)

// name は作成するリソースグループの名前
func CreateOrUpdate(ctx context.Context, subscriptionID, name, token string) error{

	// Resource API にアクセスするためのクライアントを作成
	cli := client.NewHTTPClient(strfmt.NewFormats())
	
	// リソースグループを作成するリージョン
	location := "westus2"

	// cli は API グループごとのクライアントを持っている．
	// 今回は ResourceGroups に関係するクライアントを使用．
	created, creating, err := cli.ResourceGroups.ResourceGroupsCreateOrUpdate(
		resource_groups.NewResourceGroupsCreateOrUpdateParamsWithContext(ctx).
			WithAPIVersion(ResourceAPIVersion).
			WithSubscriptionID(subscriptionID).
			WithResourceGroupName(name).
			WithParameters(&models.ResourceGroup{
				Location: &location,
			}), httptransport.BearerToken(token))
			
	if err != nil {
		return err
	}
	
	// リソースグルプが作成されて関数から返ってきた場合，created が non nil に，
	// 非同期で作成中の状態で返ってきた場合は creating が non nil になる．
	
	// 以降略
							
}
```

ResourceGroupsCreateOrUpdateParams の構築部分がごちゃごちゃしているが，大したことはしていない．


# メソッドが認証情報を受け取らない場合

先ほどとは異なり，各メソッドが認証情報を受け取らない場合，もっと低レベルなところをいじる必要がある．
具体的には，`client.NewHTTPClient(strfmt.NewFormats())` が返す API のクライアントが持っている，
Transport.DefaultAuthentication 要素に [BearerToken](https://godoc.org/github.com/go-openapi/runtime/client#BearerToken) 関数が返す [runtime.ClientAuthInfoWriter](https://godoc.org/github.com/go-openapi/runtime#ClientAuthInfoWriter) を設定する．

```go
// API にアクセスするためのクライアントを作成
cli := client.NewHTTPClient(strfmt.NewFormats())

// Transport を *httptransport.Runtime にキャストして ClientAuthInfoWriter を設定
switch transport := cli.Transport.(type) {
case *httptransport.Runtime:

	transport.DefaultAuthentication = httptransport.BearerToken(token)

	// 子クライアントからも認証情報にアクセスできるよう設定
	cli.ResourceGroups.SetTransport(transport)
	
}
```

注意点は client.NewHTTPClient が返すクライアントの Transport だけではなく，
このクライアントが持っている子クライアントの SetTranport を呼ぶ必要があることである．

ちなみに，Resource API の場合，このクライアントは，

```go
type ResourceManagementClient struct {
    DeploymentOperations *deployment_operations.Client

    Deployments *deployments.Client

    Providers *providers.Client

    ResourceGroups *resource_groups.Client

    Resources *resources.Client

    Tags *tags.Client

    Transport runtime.ClientTransport
}
```

と定義されている．今回は，ResourceGroup の Transport を更新したが，他のクライアントを使用する場合は同様に更新する必要がある．