Skip to content

Commit 5ab15dd

Browse files
Adding example
1 parent 99f484d commit 5ab15dd

File tree

6 files changed

+156
-5
lines changed

6 files changed

+156
-5
lines changed

aws_lambda_powertools/utilities/data_classes/transfer_family_event.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import json
34
from typing import Any, Literal
45

56
from aws_lambda_powertools.utilities.data_classes.common import (
@@ -62,7 +63,7 @@ def _build_authentication_response(
6263
if not home_directory_details:
6364
raise ValueError("home_directory_details must be set when home_directory_type is LOGICAL")
6465

65-
response["HomeDirectoryDetails"] = [home_directory_details]
66+
response["HomeDirectoryDetails"] = json.dumps([home_directory_details])
6667

6768
else:
6869
raise ValueError(f"Invalid home_directory_type: {home_directory_type}")

docs/utilities/data_classes.md

+28-2
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ Log Data Event for Troubleshooting
108108
| [SES](#ses) | `SESEvent` |
109109
| [SNS](#sns) | `SNSEvent` |
110110
| [SQS](#sqs) | `SQSEvent` |
111-
| [TransferFamilyAuthorizer] | `TransferFamilyAuthorizer` |
112-
| [TransferFamilyAuthorizerResponse] | `TransferFamilyAuthorizerResponse` |
111+
| [TransferFamilyAuthorizer](#transfer-family-authorizer) | `TransferFamilyAuthorizer` |
112+
| [TransferFamilyAuthorizerResponse](#transfer-family-authorizer) | `TransferFamilyAuthorizerResponse` |
113113
| [VPC Lattice V2](#vpc-lattice-v2) | `VPCLatticeV2Event` |
114114
| [VPC Lattice V1](#vpc-lattice-v1) | `VPCLatticeEvent` |
115115

@@ -1257,6 +1257,32 @@ AWS Secrets Manager rotation uses an AWS Lambda function to update the secret. [
12571257
do_something_with(record.body)
12581258
```
12591259

1260+
### Transfer Family Authorizer
1261+
1262+
AWS Transfer Family allows using Lambda as a custom identity provider. This enables integration with various identity providers like Okta, Secrets Manager, OneLogin, or custom data stores for authentication and authorization.
1263+
1264+
=== "transfer_family_authorizer_efs.py"
1265+
1266+
```python hl_lines="8 9 16 23 43"
1267+
--8<-- "examples/event_sources/src/transfer_family_authorizer_efs.py"
1268+
```
1269+
1270+
1. You can use the method `build_authentication_response_efs` to build a response to AWS Transfer Family
1271+
1272+
=== "transfer_family_authorizer_s3.py"
1273+
1274+
```python hl_lines="8 9 16 23 43"
1275+
--8<-- "examples/event_sources/src/transfer_family_authorizer_s3.py"
1276+
```
1277+
1278+
1. You can use the method `build_authentication_response_s3` to build a response to AWS Transfer Family
1279+
1280+
=== "Transfer Family Authorizer Example Event"
1281+
1282+
```json
1283+
--8<-- "examples/event_sources/src/transfer_family_authorizer_payload.json"
1284+
```
1285+
12601286
### VPC Lattice V2
12611287

12621288
You can register your Lambda functions as targets within an Amazon VPC Lattice service network. By doing this, your Lambda function becomes a service within the network, and clients that have access to the VPC Lattice service network can call your service using [Payload V2](https://docs.aws.amazon.com/lambda/latest/dg/services-vpc-lattice.html#vpc-lattice-receiving-events){target="_blank"}.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
5+
from aws_lambda_powertools import Logger
6+
from aws_lambda_powertools.utilities import parameters
7+
from aws_lambda_powertools.utilities.data_classes import (
8+
TransferFamilyAuthorizer,
9+
TransferFamilyAuthorizerResponse,
10+
event_source,
11+
)
12+
from aws_lambda_powertools.utilities.typing import LambdaContext
13+
14+
logger = Logger()
15+
16+
@event_source(data_class=TransferFamilyAuthorizer)
17+
def lambda_handler(event: TransferFamilyAuthorizer, context: LambdaContext):
18+
19+
username = event.username
20+
password = event.password or None
21+
22+
response: dict[str, Any] = {}
23+
build_response = TransferFamilyAuthorizerResponse()
24+
25+
try:
26+
user_data = parameters.get_secret(f"/sftp/{username}", transform="json")
27+
28+
logger.info(f"Credentials found for user {username}")
29+
30+
stored_username = user_data["username"]
31+
stored_secret = user_data["password"]
32+
stored_gid = user_data["gid"]
33+
stored_uid = user_data["uid"]
34+
stored_role = user_data["role"]
35+
stored_directory = user_data["efs-server"]
36+
stored_entry = user_data["entry"]
37+
stored_directory_type = user_data["directory-type"]
38+
home_directory_details = {"Entry": stored_entry, "Target": stored_directory}
39+
40+
if username == stored_username and password == stored_secret:
41+
logger.info(f"User {username} informed a valid password")
42+
43+
response = build_response.build_authentication_response_efs( # (1)!
44+
role_arn=stored_role,
45+
user_gid=stored_gid,
46+
user_uid=stored_uid,
47+
home_directory_type=stored_directory_type,
48+
home_directory_details=home_directory_details,
49+
)
50+
else:
51+
logger.info(f"User {username} informed a invalid password")
52+
53+
except Exception as e:
54+
logger.exception(e)
55+
logger.info(f"Credentials not valid for user {username}")
56+
57+
return response
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"username": "value",
3+
"password": "value",
4+
"protocol": "SFTP",
5+
"serverId": "s-abcd123456",
6+
"sourceIp": "192.168.0.100"
7+
}
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
5+
from aws_lambda_powertools import Logger
6+
from aws_lambda_powertools.utilities import parameters
7+
from aws_lambda_powertools.utilities.data_classes import (
8+
TransferFamilyAuthorizer,
9+
TransferFamilyAuthorizerResponse,
10+
event_source,
11+
)
12+
from aws_lambda_powertools.utilities.typing import LambdaContext
13+
14+
logger = Logger()
15+
16+
@event_source(data_class=TransferFamilyAuthorizer)
17+
def lambda_handler(event: TransferFamilyAuthorizer, context: LambdaContext):
18+
19+
username = event.username
20+
password = event.password or None
21+
22+
response: dict[str, Any] = {}
23+
build_response = TransferFamilyAuthorizerResponse()
24+
25+
try:
26+
user_data = parameters.get_secret(f"/sftp/{username}", transform="json")
27+
28+
logger.info(f"Credentials found for user {username}")
29+
30+
stored_username = user_data["username"]
31+
stored_secret = user_data["password"]
32+
stored_gid = user_data["gid"]
33+
stored_uid = user_data["uid"]
34+
stored_role = user_data["role"]
35+
stored_directory = user_data["efs-server"]
36+
stored_entry = user_data["entry"]
37+
stored_directory_type = user_data["directory-type"]
38+
home_directory_details = {"Entry": stored_entry, "Target": stored_directory}
39+
40+
if username == stored_username and password == stored_secret:
41+
logger.info(f"User {username} informed a valid password")
42+
43+
response = build_response.build_authentication_response_efs( # (1)!
44+
role_arn=stored_role,
45+
user_gid=stored_gid,
46+
user_uid=stored_uid,
47+
home_directory_type=stored_directory_type,
48+
home_directory_details=home_directory_details,
49+
)
50+
else:
51+
logger.info(f"User {username} informed a invalid password")
52+
53+
except Exception as e:
54+
logger.exception(e)
55+
logger.info(f"Credentials not valid for user {username}")
56+
57+
return response

tests/unit/data_classes/required_dependencies/test_transfer_family_event.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import json
2+
13
import pytest
24

35
from aws_lambda_powertools.utilities.data_classes.transfer_family_event import (
@@ -52,7 +54,7 @@ def test_build_authentication_response_s3(home_directory_type):
5254
assert response.get("HomeDirectory") == home_directory
5355
assert "HomeDirectoryDetails" not in response
5456
else:
55-
assert response.get("HomeDirectoryDetails") == [home_directory_details]
57+
assert response.get("HomeDirectoryDetails") == json.dumps([home_directory_details])
5658
assert "HomeDirectory" not in response
5759

5860

@@ -86,7 +88,7 @@ def test_build_authentication_response_efs(home_directory_type):
8688
assert response.get("HomeDirectory") == home_directory
8789
assert "HomeDirectoryDetails" not in response
8890
else:
89-
assert response.get("HomeDirectoryDetails") == [home_directory_details]
91+
assert response.get("HomeDirectoryDetails") == json.dumps([home_directory_details])
9092
assert "HomeDirectory" not in response
9193

9294

0 commit comments

Comments
 (0)