アクセストークンの取得(Python)
この例では、外部 Python スクリプトを呼び出して OAuth2 トークンを取得する方法を示します。 有効な OAuth2 アクセス トークンは、認証委任の実装で必要になります。
前提条件
サンプルを実行するには
- Python 3.10 以降をインストールします。
- プロジェクトに utils.h/cpp を実装します。
- ビルド時にバイナリと同じディレクトリにあるよう、auth.py をプロジェクトに追加します。
- Microsoft Information Protection (MIP) SDK のセットアップと構成を完了します。 特に、クライアント アプリケーションを Microsoft Entra テナントに登録します。 Microsoft Entra ID から、トークン取得ロジックで使用されるアプリケーション ID (クライアント ID とも呼ばれる) が提供されます。
このコードを運用環境で使用することは想定していません。 これは、開発と認証概念の理解のためにのみ使用できます。 サンプルはクロスプラットフォームです。
サンプル::auth::AcquireToken()
単純な認証の例では、パラメーターは取らず、ハード コーティングされたトークン値を返す、単純な AcquireToken()
関数を試しました。 この例では、AcquireToken() をオーバーロードして認証パラメーターを受け入れ、外部 Python スクリプトを呼び出してトークンを返します。
auth.h
auth.h では、AcquireToken()
がオーバーロードされており、オーバーロードされた関数と更新されたパラメーターは次のとおりです。
//auth.h
#include <string>
namespace sample {
namespace auth {
std::string AcquireToken(
const std::string& userName, //A string value containing the user's UPN.
const std::string& password, //The user's password in plaintext
const std::string& clientId, //The Azure AD client ID (also known as Application ID) of your application.
const std::string& resource, //The resource URL for which an OAuth2 token is required. Provided by challenge object.
const std::string& authority); //The authentication authority endpoint. Provided by challenge object.
}
}
最初の 3 つのパラメータは、ユーザー入力によって提供されるか、アプリケーションにハードコードされます。 最後の 2 つのパラメーターは、SDK によって認証デリゲートに提供されます。
auth.cpp
auth.cpp で、オーバーロードされた関数定義を追加し、Python スクリプトを呼び出すために必要なコードを定義します。 この関数は、提供されたすべてのパラメーターを受け入れ、Python スクリプトに渡します。 スクリプトが実行され、トークンが文字列形式で返されます。
#include "auth.h"
#include "utils.h"
#include <fstream>
#include <functional>
#include <memory>
#include <string>
using std::string;
using std::runtime_error;
namespace sample {
namespace auth {
//This function implements token acquisition in the application by calling an external Python script.
//The Python script requires username, password, clientId, resource, and authority.
//Username, Password, and ClientId are provided by the user/developer
//Resource and Authority are provided as part of the OAuth2Challenge object that is passed in by the SDK to the AuthDelegate.
string AcquireToken(
const string& userName,
const string& password,
const string& clientId,
const string& resource,
const string& authority) {
string cmd = "python";
if (sample::FileExists("auth.py"))
cmd += " auth.py -u ";
else
throw runtime_error("Unable to find auth script.");
cmd += userName;
cmd += " -p ";
cmd += password;
cmd += " -a ";
cmd += authority;
cmd += " -r ";
cmd += resource;
cmd += " -c ";
// Replace <application-id> with the Application ID provided during your Azure AD application registration.
cmd += (!clientId.empty() ? clientId : "<application-id>");
string result = sample::Execute(cmd.c_str());
if (result.empty())
throw runtime_error("Failed to acquire token. Ensure Python is installed correctly.");
return result;
}
}
}
Python Script
このスクリプトは、Python 用 Microsoft Authentication Library (MSAL) 経由で、認証トークンを直接取得します。 このコードは、サンプル アプリで認証トークンを取得するためのみに含まれており、運用環境での使用は想定していません。 このスクリプトは、プレーンな古いユーザー名/パスワード認証をサポートするテナントに対してのみ機能します。 MFA または証明書ベースの認証は、このスクリプト経由ではサポートされていません。
Note
このサンプルを実行する前に、次のいずれかのコマンドを実行して、Python 用 MSAL をインストールする必要があります。
pip install msal
pip3 install msal
import getopt
import sys
import json
import re
from msal import PublicClientApplication
def printUsage():
print('auth.py -u <username> -p <password> -a <authority> -r <resource> -c <clientId>')
def main(argv):
try:
options, args = getopt.getopt(argv, 'hu:p:a:r:c:')
except getopt.GetoptError:
printUsage()
sys.exit(-1)
username = ''
password = ''
authority = ''
resource = ''
clientId = ''
for option, arg in options:
if option == '-h':
printUsage()
sys.exit()
elif option == '-u':
username = arg
elif option == '-p':
password = arg
elif option == '-a':
authority = arg
elif option == '-r':
resource = arg
elif option == '-c':
clientId = arg
if username == '' or password == '' or authority == '' or resource == '' or clientId == '':
printUsage()
sys.exit(-1)
# ONLY FOR DEMO PURPOSES AND MSAL FOR PYTHON
# This shouldn't be required when using proper auth flows in production.
if authority.find('common') > 1:
authority = authority.split('/common')[0] + "/organizations"
app = PublicClientApplication(client_id=clientId, authority=authority)
result = None
if resource.endswith('/'):
resource += ".default"
else:
resource += "/.default"
# *DO NOT* use username/password authentication in production system.
# Instead, consider auth code flow and using a browser to fetch the token.
result = app.acquire_token_by_username_password(username=username, password=password, scopes=[resource])
print(result['access_token'])
if __name__ == '__main__':
main(sys.argv[1:])
AcquireOAuth2Tokenを更新する
最後に、AuthDelegateImpl
の AcquireOAuth2Token
関数を更新して、オーバーロードされた AcquireToken
関数を呼び出します。 challenge.GetResource()
とchallenge.GetAuthority()
を読み取ることでリソースと権限のURLが取得されます。 OAuth2Challenge
は、エンジンが追加されるときに認証デリゲートに渡されます。 この作業は SDK によって行われるため、開発者側で追加の作業は必要ありません。
bool AuthDelegateImpl::AcquireOAuth2Token(
const mip::Identity& /*identity*/,
const OAuth2Challenge& challenge,
OAuth2Token& token) {
//call our AcquireToken function, passing in username, password, clientId, and getting the resource/authority from the OAuth2Challenge object
string accessToken = sample::auth::AcquireToken(mUserName, mPassword, mClientId, challenge.GetResource(), challenge.GetAuthority());
token.SetAccessToken(accessToken);
return true;
}
engine
が追加されると、SDK は `AcquireOAuth2Token 関数を呼び出し、チャレンジを渡し、Python スクリプトを実行し、トークンを受信して、トークンをサービスに提示します。