Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

Azure Active Directory で Spring Boot and OAuth2

追記 2017/07/12

少しきれいにしたサンプルを以下に置いてあります。

github.com

Sprint Boot and OAuth2 ということで、以下にチュートリアルがあったりするわけですが、チュートリアルには、FaceBookとGithubの例が載っていたので、ふと思い立ってAzure Active Directoryでも出来るのか試してみました。結論からいうとできたのですが、全てを理解してやっているわけではないのでご注意を。もっとスマートな方法があるのではないかと思ってます。

spring.io

チュートリアル内にはいくつかサンプルがありますが、基本同じ様なことをちょっとづつ変えて試すような流れになっているぽいです。

click: adds an explicit link that the user has to click to login.

の中で↑のようなやつを少し改変しようと思います。

準備

  1. 適当にGithubからサンプルをCloneして、Eclipseあたりに放り込んでください。
  2. Azure Active Directory で アプリの登録し、テナントID、クライアントID、クライアントシークレットを入手しておきます。

application.yaml

クライアントIDとかクライアントシークレットとか、認証のURIとかはapplication.yamlに記述します。 accessTokenUriとかには、TenantIdを埋め込んでおいてください。最後のuserInfoUriですが、最終的にフレームワーク側が、このURIをアクセスしてユーザ情報を引っ張ってくるみたいですので、自身の情報が取得できURIを設定しておきます。

security:
  oauth2:
    client:
      clientId: <<your client id>>
      clientSecret: <<your client secret>>
      accessTokenUri: https://login.microsoftonline.com/<<tenantId>>/oauth2/token
      userAuthorizationUri: https://login.microsoftonline.com/<<tenantId>>/oauth2/authorize
      clientAuthenticationScheme: form
      scope: openid
    resource:
      userInfoUri: https://graph.windows.net/me?api-version=1.6

このままでも実行してアクセスするとLogin画面にリダイレクトされて認証のことろまで進みますが、エラーがでてしまいます。

Enhancer

POSTするときに、一部情報が足りないようです。RequestEnhancer を実装して新しいクラスを作成し、

resource : https://graph.windows.net/

の情報が付加されるようにしておきます。これは、Graph API というリソースにアクセスしまうというものです。

package com.example;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

@Component
public class AzureRequestEnhancerCustomizer {

    @Autowired
    private OAuth2RestTemplate userInfoRestTemplate;

    @PostConstruct
    public void testWiring() {
        AuthorizationCodeAccessTokenProvider authorizationCodeAccessTokenProvider = new AuthorizationCodeAccessTokenProvider();
        authorizationCodeAccessTokenProvider.setTokenRequestEnhancer(new AzureRequestEnhancer());
        userInfoRestTemplate.setAccessTokenProvider(authorizationCodeAccessTokenProvider);
    }
}

@Component
class AzureRequestEnhancer implements RequestEnhancer {

    public AzureRequestEnhancer() {
    }

    @Override
    public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
            MultiValueMap<String, String> form, HttpHeaders headers) {
        form.set("resource", "https://graph.windows.net");
    }
}

実行

実行してもそのままだと、名前が表示されません。とりえあず、

http://localhost:8080/user

をたたくと、JSONが返ってきますので、どんな情報が返ってくるか確認できるでしょう。

index.html を以下のように編集しておくと名前がでるかもしれません。

self.user = data.userAuthentication.details.displayName;

f:id:StateMachine:20160419155327p:plain

参考

世の中には大体やろうとしていることの先行者がいるわけでして、以下のあたりをだいぶ参考に動きを把握させてもらいました。 AzureRequestEnhancer とかは以下の部分からのコピペ&改変です。

あとは、

などです。

RBACのオペレーション一覧

RBACはカスタムロールを作ることができますが、それらの操作一覧を取得する備忘録です。

一覧表示

操作を表示するには、Get-AzureRmProviderOperation コマンドを使います。OperationSearchStringが必須引数なので、* とか指定すると全部でます。

Get-AzureRmProviderOperation -OperationSearchString "*"

VM系のを出したい場合、

Get-AzureRmProviderOperation -OperationSearchString "Microsoft.Compute/virtualMachines/*"

となります。

Out-GridViewとかで表示するとこんな感じです。

f:id:StateMachine:20160401111409p:plain

既定のVM管理者

プリセットされているVM管理者がいますが、その操作権限を表示させると以下となります。

> (Get-AzureRmRoleDefinition -Name "Virtual Machine Contributor").actions    

Microsoft.Authorization/*/read
Microsoft.Compute/availabilitySets/*
Microsoft.Compute/locations/*
Microsoft.Compute/virtualMachines/*
Microsoft.Compute/virtualMachineScaleSets/*
Microsoft.Insights/alertRules/*
Microsoft.Network/applicationGateways/backendAddressPools/join/action
Microsoft.Network/loadBalancers/backendAddressPools/join/action
Microsoft.Network/loadBalancers/inboundNatPools/join/action
Microsoft.Network/loadBalancers/inboundNatRules/join/action
Microsoft.Network/loadBalancers/read
Microsoft.Network/locations/*
Microsoft.Network/networkInterfaces/*
Microsoft.Network/networkSecurityGroups/join/action
Microsoft.Network/networkSecurityGroups/read
Microsoft.Network/publicIPAddresses/join/action
Microsoft.Network/publicIPAddresses/read
Microsoft.Network/virtualNetworks/read
Microsoft.Network/virtualNetworks/subnets/join/action
Microsoft.ResourceHealth/availabilityStatuses/read
Microsoft.Resources/deployments/*
Microsoft.Resources/subscriptions/resourceGroups/read
Microsoft.Storage/storageAccounts/listKeys/action
Microsoft.Storage/storageAccounts/read
Microsoft.Support/*

以上

Azure SDK for Java 1.0.0 beta

AutoRestに対応したJava SDK 1.0.0 beta がリリースされてます。GitHubのAutoRestブランチを参照してください。

github.com

0.9系のAPIから大幅に変更されているため互換がありません。ただ各言語共通フレームワークからの自動生成なので、各言語間のクラス構成やメソッド名などの差異が(言語差はあるとして)ありません。

pom

READMEのとおりだと、依存が見つからないのでVMを操作するときの最小限の依存関係のpomを張っておきます(備忘録)

  • compute がVMを操作するもの
  • adal4j は Azure Active Directory
  • client authenticationはクライアント認証に必要な補足的なクラス
    <dependencies>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-mgmt-compute</artifactId>
            <version>1.0.0-beta1</version>
        </dependency>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-client-authentication</artifactId>
            <version>1.0.0-beta1</version>
        </dependency>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>adal4j</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

使用例

例によってADALでアプリ登録を行い、テナントID、クライアントID、クライアントキーを取得しておき、ApplicationTokenCredentials クラスで認証を行います。 VMを操作するクラスとしてComputeManagementClientを使いますが、サブスクリプションはそこに設定するみたいです。

あとは、Operationオブジェクトを取得してVM情報を取得する流れとなります。

    private static void getVirtualMachine(
            String subscriptionId,
            String tenantId,
            String clientId,
            String clientKey)
            throws CloudException, IOException, InterruptedException {
        
        ApplicationTokenCredentials creds = new ApplicationTokenCredentials(
                clientId, tenantId, clientKey, null);

        ComputeManagementClientImpl client = new ComputeManagementClientImpl(creds);
        client.setSubscriptionId(subscriptionId);

        String rg = "your-resourece-group-name";
        String rs = "your-vm-name";
        ServiceResponse<VirtualMachine> response = client.getVirtualMachinesOperations().get(rg, rs, "instanceview");
        System.out.println(response.getBody().getName());
    }

インスタンスビューを取得するのに、第3引数に"instanceview"を指定するのは,前BLOG ARM API およびSDKでの仮想マシンの状態取得 - Azureの小ネタ (改) のとおりです。