Repository: aws-powertools/powertools-lambda-python

Issue:
Bug: Dataclass - TransferFamilyAuthorizerResponse - Wrong response build for HomeDirectoryDetails
### Expected Behaviour


Generate correct response with _build_authentication_response() method when using HomeDirectoryDetails.

### Current Behaviour

When using : _build_authentication_response() method to build a response to AWS Transfer Server with a custom lambda identity provider, AWS required a string representation of a JSON map for the HomeDirectoryDetails value.

Currently; we return a list of dict.

Second, the value can be a list of mapping, as we can see in the python lambda example in the documentation.

---

From : https://docs.aws.amazon.com/transfer/latest/userguide/custom-lambda-idp.html

```
HomeDirectoryDetails is a string representation of a JSON map. This is in contrast to PosixProfile, which is an actual JSON map object, and PublicKeys which is a JSON array of strings. See the code examples for the language-specific details.
```

### Code snippet

```python
Can't reproduce without a running AWS Transfer Server, the server return "Unable to parse Json" when the HomeDirectoryDetails is not correcly formated.
```

### Possible Solution

https://github.com/aws-powertools/powertools-lambda-python/blob/72f9d2b773820f29d51129bb6dca112f3e22750a/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py#L65

Solution :
```
response["HomeDirectoryDetails"] = json.dumps([home_directory_details]) 
```

### Steps to Reproduce

Hard to do, you need to setup a full AWS Transfert Server with lambda authorizer and return a response builded with the data class.

### Powertools for AWS Lambda (Python) version

latest

### AWS Lambda function runtime

3.12

### Packaging format used

Lambda Layers, PyPi, Serverless Application Repository (SAR) App

### Debugging logs

```python

```

Hints from issue comments:
@fabien-github: Fix here : https://github.com/fabien-github/powertools-lambda-python/commit/77c337753c524a3a95793acad7e186315acf72d3@leandrodamascena: Hey @fabien-github! Thanks a lot for opening this issue! Do you want to send a PR with that code to fix it?@github-actions: ### ⚠️COMMENT VISIBILITY WARNING⚠️
This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a [team member](https://github.com/aws-powertools/powertools-lambda-python/blob/develop/MAINTAINERS.md#current-maintainers) or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

Solution patch:
diff --git a/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py b/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py
index eecc425e5..5326a344e 100644
--- a/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py
+++ b/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import json
 from typing import Any, Literal
 
 from aws_lambda_powertools.utilities.data_classes.common import (
@@ -44,7 +45,7 @@ class TransferFamilyAuthorizerResponse:
         role_arn: str,
         policy: str | None = None,
         home_directory: str | None = None,
-        home_directory_details: dict | None = None,
+        home_directory_details: list[dict] | None = None,
         home_directory_type: Literal["LOGICAL", "PATH"] = "PATH",
         user_gid: int | None = None,
         user_uid: int | None = None,
@@ -62,7 +63,7 @@ class TransferFamilyAuthorizerResponse:
             if not home_directory_details:
                 raise ValueError("home_directory_details must be set when home_directory_type is LOGICAL")
 
-            response["HomeDirectoryDetails"] = [home_directory_details]
+            response["HomeDirectoryDetails"] = json.dumps(home_directory_details)
 
         else:
             raise ValueError(f"Invalid home_directory_type: {home_directory_type}")
@@ -88,7 +89,7 @@ class TransferFamilyAuthorizerResponse:
         user_uid: int,
         policy: str | None = None,
         home_directory: str | None = None,
-        home_directory_details: dict | None = None,
+        home_directory_details: list[dict] | None = None,
         home_directory_type: Literal["LOGICAL", "PATH"] = "PATH",
         public_keys: str | None = None,
     ) -> dict[str, Any]:
@@ -143,7 +144,7 @@ class TransferFamilyAuthorizerResponse:
         role_arn: str,
         policy: str | None = None,
         home_directory: str | None = None,
-        home_directory_details: dict | None = None,
+        home_directory_details: list[dict] | None = None,
         home_directory_type: Literal["LOGICAL", "PATH"] = "PATH",
         public_keys: str | None = None,
     ) -> dict[str, Any]:


Test patch:
diff --git a/tests/unit/data_classes/required_dependencies/test_transfer_family_event.py b/tests/unit/data_classes/required_dependencies/test_transfer_family_event.py
index 9a74c0398..2adcad63c 100644
--- a/tests/unit/data_classes/required_dependencies/test_transfer_family_event.py
+++ b/tests/unit/data_classes/required_dependencies/test_transfer_family_event.py
@@ -28,7 +28,7 @@ def test_build_authentication_response_s3(home_directory_type):
     policy = '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": "s3:*", "Resource": "*"}]}'
     home_directory = "/bucket/user" if home_directory_type == "PATH" else None
     home_directory_details = (
-        {"Entry": "/", "Target": "/bucket/${transfer:UserName}"} if home_directory_type == "LOGICAL" else None
+        [{"Entry": "/", "Target": "/bucket/${transfer:UserName}"}] if home_directory_type == "LOGICAL" else None
     )
     public_keys = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+Z"
 
@@ -52,7 +52,7 @@ def test_build_authentication_response_s3(home_directory_type):
         assert response.get("HomeDirectory") == home_directory
         assert "HomeDirectoryDetails" not in response
     else:
-        assert response.get("HomeDirectoryDetails") == [home_directory_details]
+        assert response.get("HomeDirectoryDetails") == '[{"Entry": "/", "Target": "/bucket/${transfer:UserName}"}]'
         assert "HomeDirectory" not in response
 
 
@@ -65,7 +65,7 @@ def test_build_authentication_response_efs(home_directory_type):
     role_arn = "arn:aws:iam::123456789012:role/S3Access"
     home_directory = "/bucket/user" if home_directory_type == "PATH" else None
     home_directory_details = (
-        {"Entry": "/", "Target": "/bucket/${transfer:UserName}"} if home_directory_type == "LOGICAL" else None
+        [{"Entry": "/", "Target": "/bucket/${transfer:UserName}"}] if home_directory_type == "LOGICAL" else None
     )
 
     # WHEN building an authentication response for EFS with different home directory types
@@ -86,7 +86,7 @@ def test_build_authentication_response_efs(home_directory_type):
         assert response.get("HomeDirectory") == home_directory
         assert "HomeDirectoryDetails" not in response
     else:
-        assert response.get("HomeDirectoryDetails") == [home_directory_details]
+        assert response.get("HomeDirectoryDetails") == '[{"Entry": "/", "Target": "/bucket/${transfer:UserName}"}]'
         assert "HomeDirectory" not in response
 
 
@@ -97,7 +97,7 @@ def test_build_authentication_missing_home_directory():
 
     # WHEN home_directory_details is empty and type is LOGICAL
     role_arn = "arn:aws:iam::123456789012:role/S3Access"
-    home_directory_details = {}
+    home_directory_details = []
     home_directory_type = "LOGICAL"
 
     # THEN must raise an exception