From 895c03d90d67f195ff95803936500639e1a2af93 Mon Sep 17 00:00:00 2001 From: katsuyoshi ozaki Date: Thu, 23 May 2024 18:07:22 +0900 Subject: [PATCH 1/5] Change of naming. --- ...haringActivity.kt => TokenSharingActivity.kt} | 2 +- .../test/TestFragmentActivity.kt | 4 ++-- .../ui/backup/BackupViewModel.kt | 2 +- .../ui/reader/ReaderFragment.kt | 4 ++-- .../TokenSharingFragment.kt} | 16 ++++++++-------- .../TokenSharingFragmentMenuProvider.kt} | 4 ++-- .../TokenSharingViewModel.kt} | 4 ++-- .../CredentialVerificationViewModel.kt | 2 +- .../main/res/navigation/mobile_navigation.xml | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) rename app/src/main/java/com/ownd_project/tw2023_wallet_android/{IdTokenSharingActivity.kt => TokenSharingActivity.kt} (95%) rename app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/{siop/IdTokenSharringFragment.kt => siop_vp/TokenSharingFragment.kt} (95%) rename app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/{siop/IdTokenSharingFragmentMenuProvider.kt => siop_vp/TokenSharingFragmentMenuProvider.kt} (91%) rename app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/{siop/IdTokenSharringViewModel.kt => siop_vp/TokenSharingViewModel.kt} (99%) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt similarity index 95% rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt index 53244cd..e0f7095 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/IdTokenSharingActivity.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/TokenSharingActivity.kt @@ -5,7 +5,7 @@ import androidx.appcompat.app.ActionBar import androidx.appcompat.app.AppCompatActivity import androidx.navigation.fragment.NavHostFragment -class IdTokenSharingActivity : AppCompatActivity() { +class TokenSharingActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt index 66ecb66..78c7f94 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/test/TestFragmentActivity.kt @@ -15,7 +15,7 @@ import com.ownd_project.tw2023_wallet_android.datastore.CredentialDataStore import com.ownd_project.tw2023_wallet_android.test.DummyData.generateSdJwt import com.ownd_project.tw2023_wallet_android.ui.credential_detail.CredentialDetailFragment import com.ownd_project.tw2023_wallet_android.ui.shared.Constants -import com.ownd_project.tw2023_wallet_android.ui.siop.IdTokenSharringFragment +import com.ownd_project.tw2023_wallet_android.ui.siop_vp.TokenSharingFragment import com.ownd_project.tw2023_wallet_android.utils.KeyPairUtil import com.ownd_project.tw2023_wallet_android.utils.ZipUtil import kotlinx.coroutines.launch @@ -83,7 +83,7 @@ class TestFragmentActivity : AppCompatActivity() { } // setContentView(R.layout.activity_test_fragment); // val fragment = IdTokenSharringFragment() - val fragment = IdTokenSharringFragment().apply { + val fragment = TokenSharingFragment().apply { arguments = args } val fragment3 = CredentialDetailFragment().apply { diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt index c4db2cf..8ce052e 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/backup/BackupViewModel.kt @@ -16,7 +16,7 @@ import com.ownd_project.tw2023_wallet_android.datastore.CredentialSharingHistory import com.ownd_project.tw2023_wallet_android.datastore.IdTokenSharingHistoryStore import com.ownd_project.tw2023_wallet_android.datastore.PreferencesDataStore import com.ownd_project.tw2023_wallet_android.pairwise.HDKeyRing -import com.ownd_project.tw2023_wallet_android.ui.siop.TAG +import com.ownd_project.tw2023_wallet_android.ui.siop_vp.TAG import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt index 109c9d4..8df71ec 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/reader/ReaderFragment.kt @@ -1,6 +1,6 @@ package com.ownd_project.tw2023_wallet_android.ui.reader -import com.ownd_project.tw2023_wallet_android.IdTokenSharingActivity +import com.ownd_project.tw2023_wallet_android.TokenSharingActivity import android.content.Intent import android.os.Bundle import android.view.LayoutInflater @@ -72,7 +72,7 @@ class ReaderFragment : Fragment() { } else { println(scanned) if (scanned.startsWith("openid4vp://") || scanned.startsWith("siopv2://")) { - val intent = Intent(context, IdTokenSharingActivity::class.java).apply { + val intent = Intent(context, TokenSharingActivity::class.java).apply { putExtra("siopRequest", scanned) putExtra("index", -1) // 一つ前の画面でアカウントを選択した場合のインデックス } diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt similarity index 95% rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt index f3f1b62..fba74d0 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringFragment.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragment.kt @@ -1,4 +1,4 @@ -package com.ownd_project.tw2023_wallet_android.ui.siop +package com.ownd_project.tw2023_wallet_android.ui.siop_vp import android.app.AlertDialog import android.net.Uri @@ -30,15 +30,15 @@ import com.ownd_project.tw2023_wallet_android.utils.viewBinding // todo レイアウト調整 // todo SVGをURLから表示 -class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) { +class TokenSharingFragment : Fragment(R.layout.fragment_id_token_sharring) { companion object { - private val tag = IdTokenSharringFragment::class.simpleName + private val tag = TokenSharingFragment::class.simpleName } private val binding by viewBinding(FragmentIdTokenSharringBinding::bind) private lateinit var issuerDetailBinding: FragmentIssuerDetailBinding - private val args: IdTokenSharringFragmentArgs by navArgs() + private val args: TokenSharingFragmentArgs by navArgs() private val sharedViewModel by activityViewModels() private val viewModel: IdTokenSharringViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -47,7 +47,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) { val activity = requireActivity() - val menuProvider = IdTokenSharingFragmentMenuProvider(this, activity.menuInflater) + val menuProvider = TokenSharingFragmentMenuProvider(this, activity.menuInflater) activity.addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED) viewModel.initDone.observe(viewLifecycleOwner, ::onInitDone) @@ -240,7 +240,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) { private fun onOpenSelectCredential(view: View) { Log.d(tag, "on click") - val action = IdTokenSharringFragmentDirections.actionIdTokenSharringToNavigationCertificate() + val action = TokenSharingFragmentDirections.actionIdTokenSharringToNavigationCertificate() findNavController().navigate(action) } @@ -281,7 +281,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) { val selectedCredential = sharedViewModel.selectedCredential.value if (selectedCredential != null) { // todo 複数対応 - viewModel.shareCredential(this, listOf(selectedCredential)) + viewModel.shareVpToken(this, listOf(selectedCredential)) } else { viewModel.shareIdToken(this) } @@ -319,7 +319,7 @@ class IdTokenSharringFragment : Fragment(R.layout.fragment_id_token_sharring) { if (postResult.location != null) { val url = postResult.location val cookies = postResult.cookies - val action = IdTokenSharringFragmentDirections.actionIdTokenSharringToWebViewFragment(url, cookies) + val action = TokenSharingFragmentDirections.actionIdTokenSharringToWebViewFragment(url, cookies) findNavController().navigate(action) } } diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt similarity index 91% rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt index 643a240..c85c8d1 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharingFragmentMenuProvider.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingFragmentMenuProvider.kt @@ -1,4 +1,4 @@ -package com.ownd_project.tw2023_wallet_android.ui.siop +package com.ownd_project.tw2023_wallet_android.ui.siop_vp import android.view.Menu import android.view.MenuInflater @@ -7,7 +7,7 @@ import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment import com.ownd_project.tw2023_wallet_android.R -class IdTokenSharingFragmentMenuProvider( +class TokenSharingFragmentMenuProvider( private val fragment: Fragment, private val menuInflater: MenuInflater ) : MenuProvider { diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt similarity index 99% rename from app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt rename to app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt index cf84046..2840df8 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop/IdTokenSharringViewModel.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/siop_vp/TokenSharingViewModel.kt @@ -1,4 +1,4 @@ -package com.ownd_project.tw2023_wallet_android.ui.siop +package com.ownd_project.tw2023_wallet_android.ui.siop_vp import android.content.Context import android.util.Log @@ -286,7 +286,7 @@ class IdTokenSharringViewModel : ViewModel() { } } - fun shareCredential(fragment: Fragment, credentials: List) { + fun shareVpToken(fragment: Fragment, credentials: List) { Log.d(TAG, "shareVPToken") viewModelScope.launch(Dispatchers.IO) { val result = openIdProvider.respondVPResponse(credentials) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt index 8babbe4..be21374 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/verification/CredentialVerificationViewModel.kt @@ -30,7 +30,7 @@ class CredentialVerificationViewModel : ViewModel() { val result: LiveData = _result fun verifyCredential(format: String, credential: String) { - Log.d(com.ownd_project.tw2023_wallet_android.ui.siop.TAG, "verifyCredential seed successfully") + Log.d(com.ownd_project.tw2023_wallet_android.ui.siop_vp.TAG, "verifyCredential seed successfully") viewModelScope.launch(Dispatchers.IO) { val result = JWT.verifyJwtByX5U(credential) result.fold( diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index b247f44..a0367fe 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -132,7 +132,7 @@ Date: Thu, 23 May 2024 18:07:57 +0900 Subject: [PATCH 2/5] Add custom scheme --- app/src/main/AndroidManifest.xml | 8 ++++- .../tw2023_wallet_android/MainActivity.kt | 34 +++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 133f148..b67e39a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,6 +55,12 @@ + + + + + + diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt index 7559e8a..0951afc 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/MainActivity.kt @@ -1,6 +1,7 @@ package com.ownd_project.tw2023_wallet_android import android.app.Activity +import android.content.Intent import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle @@ -78,20 +79,33 @@ class MainActivity : AppCompatActivity() { } } } - // URIからパラメータを抽出 data?.let { - // ここでパラメータを処理 - val parameterValue = it.getQueryParameter("credential_offer") // クエリパラメータの取得 - - // credential_offerがある場合発行画面に遷移する - if (!parameterValue.isNullOrEmpty()) { - val bundle = Bundle().apply { - putString("parameterValue", parameterValue) + Log.d("MainActivity", "uri: $it") + when (data.scheme) { + "openid4vp" -> { + val newIntent = Intent(this, TokenSharingActivity::class.java).apply { + putExtra("siopRequest", it.toString()) + putExtra("index", -1) + } + startActivity(newIntent) + } + "openid-credential-offer" -> { + // ここでパラメータを処理 + val parameterValue = it.getQueryParameter("credential_offer") // クエリパラメータの取得 + + // credential_offerがある場合発行画面に遷移する + if (!parameterValue.isNullOrEmpty()) { + val bundle = Bundle().apply { + putString("parameterValue", parameterValue) + } + navController.navigate(R.id.action_to_confirmation, bundle) + } + } + else -> { + Log.d("MainActivity", "unknown custom scheme: ${data.scheme}") } - navController.navigate(R.id.action_to_confirmation, bundle) } - } } From b22251f5fcfff220e20b703354110c8cc384a511 Mon Sep 17 00:00:00 2001 From: katsuyoshi ozaki Date: Fri, 24 May 2024 12:28:15 +0900 Subject: [PATCH 3/5] Add domain bound AppLink. --- app/src/main/AndroidManifest.xml | 10 ++++ .../tw2023_wallet_android/MainActivity.kt | 46 +++++++++++++------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b67e39a..ab50c5c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,16 @@ + + + + + + + + { - val newIntent = Intent(this, TokenSharingActivity::class.java).apply { - putExtra("siopRequest", it.toString()) - putExtra("index", -1) - } - startActivity(newIntent) + handleVp(it) } "openid-credential-offer" -> { - // ここでパラメータを処理 - val parameterValue = it.getQueryParameter("credential_offer") // クエリパラメータの取得 - - // credential_offerがある場合発行画面に遷移する - if (!parameterValue.isNullOrEmpty()) { - val bundle = Bundle().apply { - putString("parameterValue", parameterValue) - } - navController.navigate(R.id.action_to_confirmation, bundle) + handleOffer(it, navController) + } + "https" -> { + // App link + if (it.getQueryParameter("credential_offer").isNullOrEmpty()){ + handleVp(it) + }else{ + handleOffer(it, navController) } } else -> { - Log.d("MainActivity", "unknown custom scheme: ${data.scheme}") + Log.d("MainActivity", "unknown scheme: ${data.scheme}") } } } @@ -117,6 +112,27 @@ class MainActivity : AppCompatActivity() { } } + private fun handleOffer(uri: Uri, navController: androidx.navigation.NavController){ + // ここでパラメータを処理 + val parameterValue = uri.getQueryParameter("credential_offer") // クエリパラメータの取得 + + // credential_offerがある場合発行画面に遷移する + if (!parameterValue.isNullOrEmpty()) { + val bundle = Bundle().apply { + putString("parameterValue", parameterValue) + } + navController.navigate(R.id.action_to_confirmation, bundle) + } + } + + private fun handleVp(uri: Uri) { + val newIntent = Intent(this, TokenSharingActivity::class.java).apply { + putExtra("siopRequest", uri.toString()) + putExtra("index", -1) + } + startActivity(newIntent) + } + private var shouldLock = false private var isLocking = false From 81ddcc24ea7f4c9ff119506d10e6dc2eb82afa00 Mon Sep 17 00:00:00 2001 From: katsuyoshi ozaki Date: Fri, 24 May 2024 12:30:38 +0900 Subject: [PATCH 4/5] Implemented responses other than POST. --- .../oid/OpenIdProvider.kt | 77 ++++++++++++++++--- .../oid/OpenIdProviderTest.kt | 51 ++++++++++++ 2 files changed, 116 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt index e5b3804..0c79be1 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt @@ -21,6 +21,7 @@ import okhttp3.Request import org.bouncycastle.jce.spec.ECNamedCurveSpec import java.math.BigInteger import java.net.URI +import java.net.URLEncoder import java.security.KeyPair import java.security.PublicKey import java.security.interfaces.ECPublicKey @@ -241,7 +242,11 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio val redirectUrl = requireNotNull(authRequest.redirectUri) println("send id token to $redirectUrl") - val result = sendRequest(redirectUrl, mapOf("id_token" to idToken)) + + // As a temporary value, give DIRECT_POST a fixed value. + // It needs to be modified when responding to redirect responses. + val result = sendRequest(redirectUrl, mapOf("id_token" to idToken), ResponseMode.DIRECT_POST) + println("Received result: $result") return Either.Right(result) } catch (e: Exception) { @@ -259,6 +264,14 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio ) val presentationDefinition = this.siopRequest.presentationDefinition ?: throw IllegalArgumentException(SIOPErrors.BAD_PARAMS.message) + + // https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes + // the default Response Mode for the OAuth 2.0 code Response Type is the query encoding + // the default Response Mode for the OAuth 2.0 token Response Type is the fragment encoding + // https://openid.net/specs/openid-4-verifiable-presentations-1_0-ID2.html#section-5 + // If the parameter is not present, the default value is fragment. + val responseMode = authRequest.responseMode ?: ResponseMode.FRAGMENT + // presentationDefinition.inputDescriptors を使って選択項目でフィルター val vpTokens = credentials.mapNotNull { it -> when (it.format) { @@ -309,8 +322,17 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio } val jsonString = objectMapper.writeValueAsString(presentationSubmission) - // todo fragmentの場合はSame Deviceにリダイレクト - val redirectUrl = requireNotNull(authRequest.responseUri) + // https://openid.net/specs/openid-4-verifiable-presentations-1_0-ID2.html#name-authorization-request + // response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present + val destinationUri = if (responseMode == ResponseMode.DIRECT_POST) { + authRequest.responseUri + } else { + authRequest.redirectUri + } + if (destinationUri.isNullOrBlank()) { + return Either.Left("Unknown destination for response") + } + val body = mutableMapOf( "vp_token" to vpTokenValue, @@ -321,8 +343,8 @@ class OpenIdProvider(val uri: String, val option: ProviderOption = ProviderOptio body["state"] = state } - println("send vp token to $redirectUrl") - val result = sendRequest(redirectUrl, body) + println("send vp token to $destinationUri") + val result = sendRequest(destinationUri, body, responseMode) print("status code: ${result.statusCode}") print("location: ${result.location}") print("cookies: ${result.cookies}") @@ -506,7 +528,7 @@ fun mergeOAuth2AndOpenIdInRequestPayload( return createRequestObjectPayloadFromMap(mergedMap) } -fun sendRequest(redirectUrl: String, formData: Map): PostResult { +fun sendRequest(destinationUri: String, formData: Map, responseMode: ResponseMode): PostResult { val client = OkHttpClient.Builder() .followRedirects(false) .build() @@ -516,11 +538,42 @@ fun sendRequest(redirectUrl: String, formData: Map): PostResult formBodyBuilder.add(key, value) } val formBody = formBodyBuilder.build() - - val request = Request.Builder() - .url(redirectUrl) - .post(formBody) - .build() + val request: Request + + when (responseMode) { + ResponseMode.DIRECT_POST -> { + request = Request.Builder() + .url(destinationUri) + .post(formBody) + .build() + } + ResponseMode.QUERY, ResponseMode.FRAGMENT -> { + val uriBuilder = StringBuilder(destinationUri) + formData.forEach { (key, value) -> + if (uriBuilder.contains("?")) { + uriBuilder.append("&") + } else { + uriBuilder.append("?") + } + uriBuilder.append(URLEncoder.encode(key, "UTF-8")) + .append("=") + .append(URLEncoder.encode(value, "UTF-8")) + } + val uriWithParams = uriBuilder.toString() + val destinationUriWithParams = if (responseMode == ResponseMode.FRAGMENT) { + uriWithParams.replace("?", "#") + } else { + uriWithParams + } + request = Request.Builder() + .url(destinationUriWithParams) + .get() + .build() + } + else -> { + throw IllegalArgumentException("Unsupported response mode: $responseMode") + } + } client.newCall(request).execute().use { response -> val statusCode = response.code() @@ -534,7 +587,7 @@ fun sendRequest(redirectUrl: String, formData: Map): PostResult val uri = URI.create(location) if (!uri.isAbsolute) { // 元のURLからホスト情報を抽出して補完 - val originalUri = URI.create(redirectUrl) + val originalUri = URI.create(destinationUri) val portPart = if (originalUri.port != -1) ":${originalUri.port}" else "" location = "${originalUri.scheme}://${originalUri.host}$portPart$location" } diff --git a/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt b/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt index 9ce52cb..e8b9d48 100644 --- a/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt +++ b/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt @@ -1,5 +1,6 @@ package com.ownd_project.tw2023_wallet_android.oid +import android.util.Log import com.auth0.jwt.JWT import com.auth0.jwt.algorithms.Algorithm import com.ownd_project.tw2023_wallet_android.encodePublicKeyToJwks @@ -111,6 +112,56 @@ class OpenIdProviderTest { wireMockServer.stop() } + + @Test + fun testSendRequest() = runBlocking { + // MockWebServerに対するレスポンスを設定します。 + wireMockServer.stubFor( + WireMock.post(WireMock.urlEqualTo("/")) + .withHeader("Content-Type", WireMock.equalTo("application/x-www-form-urlencoded")) + .willReturn( + WireMock.aResponse() + .withStatus(200) + .withBody("response body") + ) + ) + + // テスト対象のメソッドを呼び出します。 + val result = sendRequest("$clientHost:${wireMockServer.port()}/", mapOf("key" to "value"), ResponseMode.DIRECT_POST) + + // レスポンスが期待通りであることを確認します。 + assertEquals(200, result.statusCode) + + // リクエストが期待通りであることを確認します。 + val recordedRequest = wireMockServer.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/"))).first() + assertEquals("POST", recordedRequest.method.toString()) + assertEquals("key=value", recordedRequest.bodyAsString) + } + + + @Test + fun testSendRequestWithQueryResponseMode() = runBlocking { + // MockWebServerに対するレスポンスを設定します。 + wireMockServer.stubFor( + WireMock.get(WireMock.urlMatching("/\\?key=value")) + .willReturn( + WireMock.aResponse() + .withStatus(200) + .withBody("response body") + ) + ) + + // テスト対象のメソッドを呼び出します。 + val result = sendRequest("$clientHost:${wireMockServer.port()}/", mapOf("key" to "value"), ResponseMode.QUERY) + + // レスポンスが期待通りであることを確認します。 + assertEquals(200, result.statusCode) + + // リクエストが期待通りであることを確認します。 + val recordedRequest = wireMockServer.findAll(WireMock.getRequestedFor(WireMock.urlMatching("/\\?key=value"))).first() + assertEquals("GET", recordedRequest.method.toString()) + } + @Test fun testProcessSIOPRequest() = runBlocking { val requestJwt = createRequestObjectJwt( From fa0c832ced197bd4e9d638ee21f417bca9b25d3e Mon Sep 17 00:00:00 2001 From: katsuyoshi ozaki Date: Fri, 31 May 2024 11:23:05 +0900 Subject: [PATCH 5/5] Since it is unclear how to send a response when the response mode is other than POST, we will not implement it for now. --- .../oid/OpenIdProvider.kt | 23 ---------------- .../oid/OpenIdProviderTest.kt | 26 +------------------ 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt index 0c79be1..2e1c849 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt @@ -547,29 +547,6 @@ fun sendRequest(destinationUri: String, formData: Map, responseM .post(formBody) .build() } - ResponseMode.QUERY, ResponseMode.FRAGMENT -> { - val uriBuilder = StringBuilder(destinationUri) - formData.forEach { (key, value) -> - if (uriBuilder.contains("?")) { - uriBuilder.append("&") - } else { - uriBuilder.append("?") - } - uriBuilder.append(URLEncoder.encode(key, "UTF-8")) - .append("=") - .append(URLEncoder.encode(value, "UTF-8")) - } - val uriWithParams = uriBuilder.toString() - val destinationUriWithParams = if (responseMode == ResponseMode.FRAGMENT) { - uriWithParams.replace("?", "#") - } else { - uriWithParams - } - request = Request.Builder() - .url(destinationUriWithParams) - .get() - .build() - } else -> { throw IllegalArgumentException("Unsupported response mode: $responseMode") } diff --git a/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt b/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt index e8b9d48..b04cb7f 100644 --- a/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt +++ b/app/src/test/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProviderTest.kt @@ -114,7 +114,7 @@ class OpenIdProviderTest { @Test - fun testSendRequest() = runBlocking { + fun testSendRequestWithDirectPost() = runBlocking { // MockWebServerに対するレスポンスを設定します。 wireMockServer.stubFor( WireMock.post(WireMock.urlEqualTo("/")) @@ -138,30 +138,6 @@ class OpenIdProviderTest { assertEquals("key=value", recordedRequest.bodyAsString) } - - @Test - fun testSendRequestWithQueryResponseMode() = runBlocking { - // MockWebServerに対するレスポンスを設定します。 - wireMockServer.stubFor( - WireMock.get(WireMock.urlMatching("/\\?key=value")) - .willReturn( - WireMock.aResponse() - .withStatus(200) - .withBody("response body") - ) - ) - - // テスト対象のメソッドを呼び出します。 - val result = sendRequest("$clientHost:${wireMockServer.port()}/", mapOf("key" to "value"), ResponseMode.QUERY) - - // レスポンスが期待通りであることを確認します。 - assertEquals(200, result.statusCode) - - // リクエストが期待通りであることを確認します。 - val recordedRequest = wireMockServer.findAll(WireMock.getRequestedFor(WireMock.urlMatching("/\\?key=value"))).first() - assertEquals("GET", recordedRequest.method.toString()) - } - @Test fun testProcessSIOPRequest() = runBlocking { val requestJwt = createRequestObjectJwt(