掲示板システム
ホーム
アクセス解析
カテゴリ
ログアウト
JWT認証によるアクセストークンの取得(主に署名生成)がうまくいかないのでご教示いただきたいです。 (ID:151477)
名前
ホームページ(ブログ、Twitterなど)のURL (省略可)
本文
DelphiXEの環境でJWT認証のアクセストークン取得のためのコードを作っていましたが、 //トークン取得ボタンイベント procedure TForm4.Button4Click(Sender: TObject); var Settings: TSettings; JWTToken: string; begin Settings := LoadSettingsFromFile(ExtractFilePath(ParamStr(0)) + AFileName); // settings.jsonはあなたのJSONファイルの名前に置き換えてください JWTToken := GetJWTToken(Settings); Memo1.lines.Add(JWTToken); end; //JSONファイルから必要なパラメータを抽出 function TForm4.LoadSettingsFromFile(const AFileName: string): TSettings; var JSON: TJSONObject; BoxAppSettings: TJSONObject; AppAuth: TJSONObject; Pair: TJSONPair; JSONStringList: TStringList; Value: string; begin try JSON := TJSONObject.ParseJSONValue(TFile.ReadAllText(AFileName)) as TJSONObject; if JSON = nil then raise Exception.Create('Failed to parse JSON file'); // ShowMessage(JSON.ToString); // Create a TStringList and add the JSON string to it JSONStringList := TStringList.Create; try JSONStringList.Text := JSON.ToString; // Save the JSON content to a file for inspection JSONStringList.SaveToFile('JSONContent.txt'); finally JSONStringList.Free; end; Pair := JSON.Get('boxAppSettings'); if Pair = nil then raise Exception.Create('boxAppSettings not found in JSON file'); if not (Pair.JsonValue is TJSONObject) then raise Exception.Create('boxAppSettings is not a JSON object'); BoxAppSettings := Pair.JsonValue as TJSONObject; Pair := BoxAppSettings.Get('clientID'); if Pair = nil then raise Exception.Create('clientID not found in boxAppSettings'); // Now you can use Pair.JsonValue.Value Pair := BoxAppSettings.Get('clientSecret'); if Pair = nil then raise Exception.Create('clientSecret not found in boxAppSettings'); // Now you can use Pair.JsonValue.Value AppAuth := BoxAppSettings.Get('appAuth').JsonValue as TJSONObject; Pair := AppAuth.Get('publicKeyID'); if Pair = nil then raise Exception.Create('publicKeyID not found in appAuth'); Result.boxAppSettings.appAuth.publicKeyID := Pair.JsonValue.Value; Pair := AppAuth.Get('privateKey'); if Pair = nil then raise Exception.Create('privateKey not found in appAuth'); Result.boxAppSettings.appAuth.privateKey := Pair.JsonValue.Value; Pair := AppAuth.Get('passphrase'); if Pair = nil then raise Exception.Create('passphrase not found in appAuth'); Result.boxAppSettings.appAuth.passphrase := Pair.JsonValue.Value; Result.boxAppSettings.clientID := BoxAppSettings.Get('clientID').JsonValue.Value; Result.boxAppSettings.clientSecret := BoxAppSettings.Get('clientSecret').JsonValue.Value; Result.boxAppSettings.appAuth.publicKeyID := AppAuth.Get('publicKeyID').JsonValue.Value; Result.boxAppSettings.appAuth.privateKey := AppAuth.Get('privateKey').JsonValue.Value; Result.boxAppSettings.appAuth.passphrase := AppAuth.Get('passphrase').JsonValue.Value; Result.enterpriseID := JSON.Get('enterpriseID').JsonValue.Value; finally JSON.Free; end; end; //トークンの取得 function TForm4.GetJWTToken(const ASettings: TSettings): string; var IdHTTP: TIdHTTP; SSLHandler: TIdSSLIOHandlerSocketOpenSSL; Params: TStringList; Header, Payload, Signature: string; begin // OpenSSL の初期化 // if not InitializeOpenSSL then // raise Exception.Create('Failed to initialize OpenSSL'); IdHTTP := TIdHTTP.Create(nil); SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP); Params := TStringList.Create; try SetHttpSSL(IdHTTP); IdHTTP.IOHandler := SSLHandler; SSLHandler.SSLOptions.Method := sslvSSLv23; IdHTTP.IOHandler := SSLHandler; IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded'; Params.Values['client_id'] := ASettings.boxAppSettings.clientID; Params.Values['client_secret'] := ASettings.boxAppSettings.clientSecret; Params.Values['grant_type'] := 'client_credentials'; // JWTトークンの生成 Header := Base64Encode('{"alg":"SHA256","typ":"JWT"}'); Payload := Base64Encode('{"iss":"' + ASettings.boxAppSettings.clientID + '","sub":"' + ASettings.boxAppSettings.appAuth.publicKeyID + '"}'); Signature := GenerateSignature(Header + '.' + Payload, ASettings.boxAppSettings.appAuth.privateKey, ASettings.boxAppSettings.appAuth.passphrase); // ここで秘密鍵を使用して署名を生成します // ヘッダ、ペイロード、署名の値を表示 Memo1.Lines.Add('Header: ' + Header); Memo1.Lines.Add('Payload: ' + Payload); Memo1.Lines.Add('Signature: ' + Signature); Params.Values['assertion'] := Header + '.' + Payload + '.' + Signature; // Memo1.Lines.Add(Header + '.' + Payload + '.' + Signature); Result := IdHTTP.Post('https://api.box.com/oauth2/token', Params); finally Params.Free; SSLHandler.Free; IdHTTP.Free; end; end; //Base64エンコード function TForm4.Base64Encode(const AValue: string): string; var Encoder: TIdEncoderMIME; begin Encoder := TIdEncoderMIME.Create(nil); try Result := Encoder.Encode(AValue); // Remove padding // Result := StringReplace(Result, '=', '', [rfReplaceAll]); finally Encoder.Free; end; end; function ExtractPrivateKey(const APEM: AnsiString; const APassword: AnsiString): TBytes; var Bio: PBIO; PKey: PEVP_PKEY; Len: Integer; PEMAsASCII: AnsiString; begin // PEM形式の秘密鍵をASCIIに変換 PEMAsASCII := AnsiString(APEM); // PEMAsASCII の終端に null 文字を追加する PEMAsASCII := PEMAsASCII + AnsiChar(#0); // 正しい長さを指定して BIO を作成する Bio := BIO_new_mem_buf(PAnsiChar(PEMAsASCII), Length(PEMAsASCII) * SizeOf(AnsiChar)); if Bio = nil then raise Exception.Create('Failed to create BIO'); try // 秘密鍵をPEMからEVP_PKEYにデコード PKey := PEM_read_bio_PrivateKey(Bio, nil, nil, PAnsiChar(APassword)); if PKey = nil then raise Exception.Create('Failed to read private key'); try // EVP_PKEYからバイト配列に変換 Len := i2d_PrivateKey(PKey, nil); SetLength(Result, Len); i2d_PrivateKey(PKey, @Result[0]); finally EVP_PKEY_free(PKey); end; finally BIO_free(Bio); end; end; function TForm4.GenerateSignature(const AData: string; AKey: AnsiString; APassword: AnsiString): string; var HMAC: TIdHMAC; Signature: TIdBytes; Key: TBytes; begin HMAC := TIdHMACSHA256.Create; try Key := ExtractPrivateKey(AKey, APassword); HMAC.Key := Key; Signature := HMAC.HashValue(TIdTextEncoding.UTF8.GetBytes(AData)); Result := TIdEncoderMIME.EncodeBytes(Signature); finally HMAC.Free; end; end; というコードを作ったところ、 Bio := BIO_new_mem_buf(PAnsiChar(PEMAsASCII), Length(PEMAsASCII) * SizeOf(AnsiChar)); をステップ実行した時点で一度に多数の例外が発生してしまいました。 PEMも'-----BEGIN ENCRYPTED PRIVATE KEY-----‘と’-----END ENCRYPTED PRIVATE KEY-----'で囲まれた適切になものになっているように見えるので、なにが原因なのか自分ではわかりません。 uses節でIdHMACSHA256を宣言できなかったため、OpenSSLの関数からIdHMACSHA256の署名を作りたいのですが、良い修正方法はありませんか。 ご教示いただけると嬉しいです。よろしくお願いいたします。
←解決時は質問者本人がここをチェックしてください。
戻る
掲示板システム
Copyright 2021 Takeshi Okamoto All Rights Reserved.