からめもぶろぐ。

俺たちは雰囲気で OAuth をやっている

Power Apps オンライン勉強会に登壇しました

ぼーっとしてたら月が替わってしまったのですが、2021/02/19 に Power Apps オンライン勉強会に登壇しました。

powerapps.connpass.com

スライドは Speaker Deck にアップロードしています。

Power Apps 勉強会にもかかわらず半分以上スクラムの話をしているというハードな内容で申し訳ありませんでした。ただ、スクラムではなくても、アプリの ALM を考えることは大事だと思いますので、単に作ればいいというのではなく、リリースしたあともアプリを育てていくことを考えていただければと思います。

Azure Active Directory のアプリケーションをコマンド ラインから作成する

今まで Azure Active Directory のアプリケーションはいつも Azure Portal から作っていたのですが、展開するときにコード化されていないと困るので、やる方法をまとめてみました。いくつか方法があって苦労したので雑にまとめておきます。

使ってみた

AzureAD モジュール

New-AzureADApplication を使ってアプリケーションを作成することができます。

docs.microsoft.com

使ってみたところ以下の問題点がありました。

  • PowerShell Core に対応していない
  • パラメーターが超絶的に面倒くさい

Az モジュール

New-AzADApplication を使ってアプリケーションを作成することができます。

docs.microsoft.com

使ってみたところ以下の問題点がありました。

  • 設定できるパラメーターが少ない
    • 例えば oauth2AllowImplicitFlow などが指定できないです。
  • IdentifierUris を省略できない

Azure CLI

az ad app create を使ってアプリケーションを作成することができます。

docs.microsoft.com

使ってみたところ以下の問題点がありました。

  • 戻り値が受け取りにくい
    • アプリケーションを作成したあとにアプリケーション ID を使って後続の処理をするときが困ったりする。
  • 同じ名前のアプリケーションを作ることができない
    • すでに存在する同じ名前のアプリケーションの情報が自動的に上書きされます。

Microsoft.Graph モジュール

New-MgApplication を使ってアプリケーションを作成することができます。

github.com

使ってみたところ以下の問題点がありました。

  • パラメーターの形式がマニフェストの定義と若干異なる

まとめ

とりあえず Microsoft.Graph モジュールがよさそう。

Microsoft Teams Toolkit で TypeScript を使えるようにする

前回の記事では Microsoft Teams Toolkit を使ってアプリを実行するまでの手順を確認しました。

blog.karamem0.jp

記事中にも説明した通り、Microsoft Teams Toolkit の既定の言語は JavaScript です。しかし、モダン開発を行う上で TypeScript を使うことは必須とも言えます。そこで、Microsoft Teams Toolkit で作成したプロジェクトで TypeScript を扱うことができるようにしたいと思います。

拡張子の変更

JavaScript の拡張子である .js ファイルを TypeScript のものに変更します。通常の TypeScript の拡張子は .ts ですが、React の JSX を扱う場合は拡張子は .tsx となります。以下のファイルの拡張子を変更します。

  • src
    • index.js => index.tsx
    • components
      • App.js => App.tsx
      • Privacy.js => Privacy.tsx
      • Tab.js => Tab.tsx
      • TermsOfUse.js => TermsOfUse.tsx

型定義パッケージのインストール

React の標準パッケージを型解決できるように型定義パッケージをインストールします。

  • @types/react
  • @types/react-dom
  • @types/react-router-dom
npm install @types/react @types/react-dom @types/react-router-dom --save-dev

TypeScript のインストール

TypeScript のパッケージをインストールします。

  • typescript
npm install typescript

TypeScript のトランスパイルには tsconfig.json が必要なのですが、初回に npm run start したときに自動的に生成されますので、いったんはそのままで問題ないです。

Tab.tsx の修正

Tab.tsx が型解決できずにエラーになるので修正します。

interface の追加

React のコンポーネントには PropsState がありますがこれを interface で定義します。

interface ITabProps { }
interface ITabState {
  context: microsoftTeams.Context
}

クラス定義の修正

コンポーネントの継承をジェネリックになるように変更します。

class Tab extends React.Component<ITabProps, ITabState> {
  ...
}

コンストラクタの修正

コンストラクタでは型を指定するようにします。

constructor(props: ITabProps) {
  super(props)
  this.state = {
    context: {} as microsoftTeams.Context
  }
}

componentDidMount の修正

microsoftTeams.getContext のコールバックが定義と合わずにエラーになっているのでパラメーターの error を削除します。

componentDidMount() {
  microsoftTeams.getContext((context) => {
    this.setState({
      context: context
    });
  });
}

これで npm run start すればコンパイルが成功するはずです。ちなみに、そもそも React ではクラス コンポーネントではなく関数コンポーネントを使うようになってきていますので、まるっと書き直してしまったほうが速いかもしれません。さっくりと書き直した場合、こんな感じになります。

import React from 'react';
import './App.css';
import * as microsoftTeams from "@microsoft/teams-js";

const Tab: React.FC = () => {

  const [context, setContext] = React.useState<microsoftTeams.Context>();
  const [userName, setUserName] = React.useState<string>();

  React.useEffect(() => {
    microsoftTeams.getContext((value) => {
      setContext(value);
    });
  }, []);

  React.useEffect(() => {
    if (context) {
      setUserName(Object.keys(context).length > 0 ? context['upn'] : "");
    }
  }, [context]);

  return (
    <div>
      <h3>Hello World!</h3>
      <h1>Congratulations {userName}!</h1> <h3>This is the tab you made :-)</h3>
    </div>
  );

}

export default Tab;

Microsoft Teams Toolkit を使って Teams アプリの開発環境を構築する

Teams アプリの開発をこれから始めるというときに環境構築のための機能がいくつか提供されています。

  • Yeoman ジェネレーター (Yo teams)
  • Microsoft Teams Toolkit

Yeoman ジェネレーターについては Microsoft Learn で使用方法が説明されています。

docs.microsoft.com

Global Microsoft 365 Developer Bootcamp でもお話しさせていただきました。

blog.karamem0.jp

もう一つの Microsoft Teams Toolkit での Teams アプリについて、Yeoman ジェネレーターとの違いや、実際に構築してみてのハマリどころをまとめてみたいと思います。

Yeoman ジェネレーターと Microsoft Teams Toolkit の違い

どちらも React を使ったアプリを構築できるという点では同じですがいくつかの相違点があります。

Yeoman ジェネレーター Microsoft Teams Toolkit
言語 TypeScript JavaScript
タスク ランナー gulp react-scripts
ngrok あり なし

Yeoman ジェネレーターのほうがいろいろ親切ではありますが、Microsoft Teams Toolkit は create-react-app で作ったのに近い構成になるため、React に慣れている人には扱いやすいです。個人的には、よりシンプルな Microsoft Teams Toolkit で始めるのをお勧めしたいです。

Microsoft Teams Toolkit を使ったプロジェクトの作成

Microsoft Teams Toolkit は Visual Studio Code の拡張機能です。なのでまずは Visual Studio Code で拡張機能をインストールします。

f:id:karamem0:20210211143724p:plain

インストールするとアクティビティー バーに Microsoft Teams のアイコンが追加されるのでクリックします。[Create a new Teams app] をクリックします。サインインを要求されるので Teams アプリをホストするテナントのアカウントでサインインします。

f:id:karamem0:20210211143727p:plain

[Tab] を選択して [Next] をクリックします。

f:id:karamem0:20210211143740p:plain

[Finish] をクリックします。ワークスペースの保存先を聞かれるので任意のフォルダーを選択します。

f:id:karamem0:20210211144250p:plain

ワークスペースが Visual Studio Code で開きます。

f:id:karamem0:20210211144300p:plain

ターミナルで以下のコマンドを実行します。

npm install
npm run start

デバッグを開始するとブラウザーが起動します。*1

f:id:karamem0:20210211144921p:plain

[追加] をクリックします。

f:id:karamem0:20210211145211p:plain

アプリが表示されるはずですが、実は表示されません。これは localhost を HTTPS で起動しているのに証明書が正しくないことが原因です。なので自己証明書を作成してエラーが出ないようにする必要があります。

f:id:karamem0:20210211145254p:plain

自己証明書の作成と設定

Windows PowerShell (PowerShell 7 では駄目です) を管理者として起動し以下のコマンドを実行します。

 New-SelfSignedCertificate -Subject "localhost" -DnsName "localhost" -NotAfter "2099/12/31" -CertStoreLocation "cert:\CurrentUser\My"

作成した証明書を秘密キーをつけて pfx ファイルとしてエクスポートします。

f:id:karamem0:20210211154249p:plain

エクスポートした pfx ファイルを [信頼されたルート証明機関] にインポートします。

f:id:karamem0:20210211154401p:plain

OpenSSL を使って以下のコマンドを実行します。

openssl pkcs12 -in localhost.pfx -nocerts -nodes -out localhost.key
openssl pkcs12 -in localhost.pfx -clcerts -nokeys -out localhost.crt

ワークスペースに cert というフォルダーを作成して localhost.key と localhost.crt をコピーします。.env ファイルに以下を追加します。

SSL_CRT_FILE=./cert/localhost.crt
SSL_KEY_FILE=./cert/localhost.key

パラメーターの意味については公式ドキュメントを参照してください。

create-react-app.dev

さてこれで準備ができたので再度 npm run start を実行しデバッグを開始します。

f:id:karamem0:20210211155340p:plain

表示されました!

まとめ

よく Teams アプリの開発をするときに「ngrok は必須です」という話を見ますが、見ていただいたとおり必須ではなく、localhost でも実行可能です。ただし、HTTPS であることは必須なので、今回の手順のように自己証明書を用意するか、ngrok を使うということになります。ただ Microsoft Teams Toolkit の場合、ngrok だと URL がランダムになってしまうので大変かもしれません。Yeoman ジェネレーターはそのあたりよろしくやってくれます。

*1:うまくいかない場合は Visual Studio Code の Debugger for Chrome や Debugger for Microsoft Edge がインストールされていない可能性があります。

Microsoft 365 に設定したプロフィール画像を削除する

Microsoft 365 に設定したプロフィール画像を削除したいという要望があったのですが、なかなか一筋縄ではいかなかったので備忘録としてメモしておきます。なお結論としては、現状としては GUI からは削除することはできず、PowerShell を使って削除する必要があります。

そもそもですが、Microsoft 365 でプロフィール画像を登録する場所は複数あります。

場所 画像の登録 画像の削除
Azure ポータル できる できる
Microsoft 365 管理センター できる できない
Delve できる できない
Outlook できる できない
Microsoft Teams できる できる ※

画像の登録はいずれの場所で行ってもそれぞれのサービスに反映されるようです。ですが、画像の削除に関しては、そもそもできなかったり、ほかのサービスへの反映がされなかったりします。Microsoft Teams の場合は、削除をすると、イニシャル画像(氏名が Takashi Shinohara であれば TS と表示される画像)が代わりに登録され、削除という動作にはなりません。ややこしいですね。

登録する場所はいろいろあるのですが、最終的に保存される場所は Azure Active Directory と Exchange の 2 つのようです。ほかにも SharePoint のユーザー プロファイルというのもあるのですが、現在どこで使われているのかを見つけることができませんでした。それぞれの画像は PowerShell で確認できます。

保存場所 コマンドレット
Azure Active Directory Get-AzureADUserThumbnailPhoto
Exchange Get-UserPhoto

Azure Active Directory の画像は Azure ポータルから GUI で削除することができますが、PowerShell では削除することはできないようです。逆に Exchange の画像は GUI から削除できず、Remove-UserPhoto コマンドレットを実行する必要があります。

ということで、現時点で Microsoft 365 からプロフィール画像を完全に削除するには以下の手順で行います。

  1. Azure ポータルから画像を削除する
  2. Remove-UserPhoto コマンドレットを実行して画像を削除する