saamfi-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Universidad ICESI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
4
+ include requirements-dev.txt
5
+ recursive-include saamfi_sdk *.py
6
+ recursive-include saamfi_sdk py.typed
7
+ recursive-exclude tests *
8
+ recursive-exclude docs *
9
+ global-exclude __pycache__
10
+ global-exclude *.py[co]
@@ -0,0 +1,257 @@
1
+ Metadata-Version: 2.4
2
+ Name: saamfi-sdk
3
+ Version: 0.1.0
4
+ Summary: SDK de Python para conectarse a los servicios SAAMFI - Autenticacion y Autorizacion
5
+ Author-email: Universidad ICESI <dev@icesi.edu.co>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/icesi-dev/saamfi-sdk-python
8
+ Project-URL: Documentation, https://saamfi-sdk-python.readthedocs.io
9
+ Project-URL: Repository, https://github.com/icesi-dev/saamfi-sdk-python.git
10
+ Project-URL: Issues, https://github.com/icesi-dev/saamfi-sdk-python/issues
11
+ Keywords: saamfi,authentication,authorization,jwt,security,sdk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: requests>=2.31.0
27
+ Requires-Dist: PyJWT>=2.8.0
28
+ Requires-Dist: cryptography>=41.0.0
29
+ Requires-Dist: pydantic>=2.5.0
30
+ Requires-Dist: python-dotenv>=1.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: black>=23.0.0; extra == "dev"
36
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
38
+ Requires-Dist: isort>=5.12.0; extra == "dev"
39
+ Provides-Extra: fastapi
40
+ Requires-Dist: fastapi>=0.104.0; extra == "fastapi"
41
+ Dynamic: license-file
42
+
43
+ ## Saamfi SDK para Python
44
+
45
+ Cliente oficial en Python para integrar sistemas con los servicios de autenticacion y autorizacion de Saamfi. Este SDK expone las mismas operaciones disponibles en la libreria Java (`SaamfiDelegate`) y simplifica la validacion de tokens JWT, la autenticacion de usuarios y la consulta de informacion institucional.
46
+
47
+ ---
48
+
49
+ ## Instalacion
50
+
51
+ - **Desde PyPI**
52
+ ```bash
53
+ pip install saamfi-sdk
54
+ ```
55
+ - **Desde el codigo fuente**
56
+ ```bash
57
+ git clone https://github.com/saamfi/saamfi-sdk-python.git
58
+ cd saamfi-sdk-python
59
+ pip install -e .
60
+ ```
61
+
62
+ Configura las siguientes variables de entorno antes de usar el cliente (por ejemplo en un archivo `.env`):
63
+
64
+ - `SAAMFI_BASE_URL`: URL base del servicio Saamfi (`https://api.saamfi.com`).
65
+ - `SAAMFI_SYS_ID`: Identificador del sistema o tenant asignado por Saamfi.
66
+ - `SAAMFI_TENANT_ID` *(opcional)*: Identificador de institución (para endpoints como `/institutions/{instid}/params`).
67
+ - `SAAMFI_CLIENT_ID` y `SAAMFI_CLIENT_SECRET` *(opcionales)*: Credenciales del sistema si tu integración las requiere.
68
+ - `SAAMFI_TEST_USERNAME` y `SAAMFI_TEST_PASSWORD` *(solo para pruebas locales)*: Usuario demo del sandbox.
69
+
70
+ > El cliente mantiene compatibilidad con las variables antiguas `SAAMFI_URL`, `SAAMFI_SYSTEM_ID` y `SAAMFI_INST_ID`.
71
+
72
+ ---
73
+
74
+ ## Quickstart
75
+
76
+ ```python
77
+ from saamfi_sdk import SaamfiClient
78
+
79
+ client = SaamfiClient() # Usa SAAMFI_BASE_URL y SAAMFI_SYS_ID desde el entorno
80
+
81
+ response = client.login("usuario@example.com", "clave-segura")
82
+ if response:
83
+ print(f"Token: {response.access_token}")
84
+ token_info = client.validate_token(response.access_token)
85
+ print(f"Roles: {token_info.roles}")
86
+ else:
87
+ print("Credenciales invalidas")
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Sandbox local con docker compose
93
+
94
+ 1. Levanta el entorno local de Saamfi con `docker compose` (puerto `9091` según la configuración compartida).
95
+ 2. Crea un archivo `.env` junto al proyecto del SDK con las variables:
96
+ ```
97
+ SAAMFI_BASE_URL=http://localhost:9091/iaslab/saamfiapi
98
+ SAAMFI_SYS_ID=8
99
+ SAAMFI_CLIENT_ID=8
100
+ SAAMFI_CLIENT_SECRET=qYr6-CxZP9t4vN2eFM1sR4gL
101
+ SAAMFI_TENANT_ID=1
102
+ SAAMFI_TEST_USERNAME=testuser
103
+ SAAMFI_TEST_PASSWORD=password123
104
+ ```
105
+ 3. Ejecuta el script de ejemplo:
106
+ ```bash
107
+ python examples/sandbox_demo.py
108
+ ```
109
+ Verás el flujo completo: descarga de clave pública, descubrimiento de sistemas/instituciones, autenticación del usuario demo, validación del JWT y consultas protegidas.
110
+
111
+ > Consulta los logs del backend en `saamfi-rest/logs/saamfi.log` o mediante `GET /logs/` (requiere rol `Query-server-logs`) para corroborar las operaciones.
112
+
113
+ ---
114
+
115
+ ## Ejemplos por funcionalidad
116
+
117
+ Cada metodo del cliente refleja una operacion del servicio Saamfi. Los siguientes fragmentos muestran el flujo completo con un token valido (`token`):
118
+
119
+ - **Obtener llave publica**
120
+ ```python
121
+ public_key = client.get_public_key()
122
+ ```
123
+
124
+ - **Autenticar usuario**
125
+ ```python
126
+ login = client.login("usuario@example.com", "clave")
127
+ ```
128
+
129
+ - **Validar token y extraer datos**
130
+ ```python
131
+ token_info = client.validate_token(token)
132
+ print(token_info.username, token_info.roles)
133
+ ```
134
+
135
+ - **Roles desde un JWT**
136
+ ```python
137
+ roles = client.get_roles_from_jwt(token)
138
+ ```
139
+
140
+ - **Informacion detallada de usuario**
141
+ ```python
142
+ user = client.get_user_info(token, user_id=12345)
143
+ ```
144
+
145
+ - **Buscar usuario por username**
146
+ ```python
147
+ user = client.get_user_by_username(token, "john.doe")
148
+ ```
149
+
150
+ - **Buscar usuarios por documentos**
151
+ ```python
152
+ users = client.get_users_by_document(token, ["100200300", "999888777"])
153
+ ```
154
+
155
+ - **Obtener usuarios por lista de IDs**
156
+ ```python
157
+ users_json = client.get_users_from_list(token, [1, 2, 3])
158
+ ```
159
+
160
+ - **Busqueda generica por parametro y valor**
161
+ ```python
162
+ result_json = client.get_users_by_param_and_value(token, "email", "example.com")
163
+ ```
164
+
165
+ - **Consultar institucion por NIT**
166
+ ```python
167
+ institution_json = client.get_institution_by_nit(token, "900123456-7")
168
+ ```
169
+
170
+ - **Consultar instituciones por IDs**
171
+ ```python
172
+ institutions_json = client.get_institutions_by_ids(token, [10, 20, 30])
173
+ ```
174
+
175
+ - **Listado público de sistemas e instituciones**
176
+ ```python
177
+ systems = client.list_public_systems()
178
+ institutions = client.list_public_institutions()
179
+ ```
180
+
181
+ - **Parámetros de institución**
182
+ ```python
183
+ params = client.get_institution_params(token) # Usa SAAMFI_TENANT_ID por defecto
184
+ ```
185
+
186
+ - **Roles configurados para un sistema**
187
+ ```python
188
+ roles = client.get_system_roles(token) # Usa SAAMFI_SYS_ID por defecto
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Referencia de API
194
+
195
+ ### Clases principales
196
+
197
+ | Clase | Descripcion |
198
+ | ----- | ----------- |
199
+ | `SaamfiClient` | Cliente principal; gestiona autenticacion, validacion y consultas. |
200
+ | `LoginBody` | Modelo para solicitudes de login. |
201
+ | `LoginResponse` | Respuesta de autenticacion exitosa. |
202
+ | `UserInfo` | Informacion detallada de usuario. |
203
+ | `UserDetailToken` | Datos extraidos de un JWT validado. |
204
+
205
+ ### Metodos clave de `SaamfiClient`
206
+
207
+ | Metodo | Entrada | Salida | Nota |
208
+ | ------ | ------- | ------ | ---- |
209
+ | `get_public_key()` | - | `RSAPublicKey` | Obtiene y cachea la llave publica. |
210
+ | `login(username, password)` | `str`, `str` | `LoginResponse | None` | Autentica usuario. |
211
+ | `get_roles_from_jwt(auth_token)` | `str` | `List[str]` | Extrae claim `role`. |
212
+ | `validate_token(auth_token)` | `str` | `UserDetailToken` | Valida firma y claims. |
213
+ | `get_user_info(auth_token, user_id)` | `str`, `int` | `UserInfo | None` | Consulta usuario por ID. |
214
+ | `get_user_by_username(auth_token, username)` | `str`, `str` | `dict | None` | Consulta POST por username. |
215
+ | `get_users_by_document(auth_token, user_documents)` | `str`, `List[str]` | `List[dict]` | Busca por multiples documentos. |
216
+ | `get_users_from_list(auth_token, user_ids)` | `str`, `List[int]` | `str | None` | JSON con usuarios por ID. |
217
+ | `get_users_by_param_and_value(auth_token, param, value)` | `str`, `str`, `str` | `str | None` | Filtro generico usando query string. |
218
+ | `get_institution_by_nit(auth_token, nit)` | `str`, `str` | `str | None` | Consulta institucion por NIT. |
219
+ | `get_institutions_by_ids(auth_token, institution_ids)` | `str`, `List[int]` | `str | None` | Consulta masiva por IDs. |
220
+ | `list_public_institutions()` | - | `List[dict] | None` | Descubrimiento de instituciones disponibles. |
221
+ | `get_institution_params(auth_token, institution_id=None)` | `str`, `Optional[int]` | `dict | None` | Obtiene parámetros de configuración institucional. |
222
+ | `list_public_systems()` | - | `List[dict] | None` | Descubrimiento de sistemas publicados. |
223
+ | `get_system_roles(auth_token, system_id=None)` | `str`, `Optional[int]` | `List[dict] | None` | Roles disponibles para un sistema. |
224
+
225
+ > Consulta los docstrings en `saamfi_sdk/client.py` para conocer detalles, equivalencias con la version Java y ejemplos adicionales.
226
+
227
+ ---
228
+
229
+ ## Manejo de errores
230
+
231
+ Todas las excepciones del SDK heredan de `SaamfiException`:
232
+
233
+ | Excepcion | Cuándo ocurre |
234
+ | --------- | ------------- |
235
+ | `SaamfiAuthenticationError` | Credenciales invalidas o token sin permisos. |
236
+ | `SaamfiTokenValidationError` | Token expirado, mal formado o con claims faltantes. |
237
+ | `SaamfiConnectionError` | Problemas de red o respuestas no exitosas del backend. |
238
+ | `SaamfiInvalidSystemError` | El token pertenece a otro `system_id`. |
239
+ | `SaamfiUnauthorizedError` | El usuario autenticado no tiene permisos para la operacion. |
240
+ | `SaamfiNotFoundError` | El recurso solicitado no existe. |
241
+
242
+ ```python
243
+ from saamfi_sdk import SaamfiClient
244
+ from saamfi_sdk.exceptions import SaamfiConnectionError, SaamfiAuthenticationError
245
+
246
+ client = SaamfiClient()
247
+
248
+ try:
249
+ login = client.login("usuario@example.com", "clave")
250
+ except SaamfiConnectionError as exc:
251
+ print(f"No es posible comunicar con Saamfi: {exc}")
252
+ except SaamfiAuthenticationError:
253
+ print("Credenciales invalidas")
254
+ ```
255
+
256
+ ---
257
+
@@ -0,0 +1,215 @@
1
+ ## Saamfi SDK para Python
2
+
3
+ Cliente oficial en Python para integrar sistemas con los servicios de autenticacion y autorizacion de Saamfi. Este SDK expone las mismas operaciones disponibles en la libreria Java (`SaamfiDelegate`) y simplifica la validacion de tokens JWT, la autenticacion de usuarios y la consulta de informacion institucional.
4
+
5
+ ---
6
+
7
+ ## Instalacion
8
+
9
+ - **Desde PyPI**
10
+ ```bash
11
+ pip install saamfi-sdk
12
+ ```
13
+ - **Desde el codigo fuente**
14
+ ```bash
15
+ git clone https://github.com/saamfi/saamfi-sdk-python.git
16
+ cd saamfi-sdk-python
17
+ pip install -e .
18
+ ```
19
+
20
+ Configura las siguientes variables de entorno antes de usar el cliente (por ejemplo en un archivo `.env`):
21
+
22
+ - `SAAMFI_BASE_URL`: URL base del servicio Saamfi (`https://api.saamfi.com`).
23
+ - `SAAMFI_SYS_ID`: Identificador del sistema o tenant asignado por Saamfi.
24
+ - `SAAMFI_TENANT_ID` *(opcional)*: Identificador de institución (para endpoints como `/institutions/{instid}/params`).
25
+ - `SAAMFI_CLIENT_ID` y `SAAMFI_CLIENT_SECRET` *(opcionales)*: Credenciales del sistema si tu integración las requiere.
26
+ - `SAAMFI_TEST_USERNAME` y `SAAMFI_TEST_PASSWORD` *(solo para pruebas locales)*: Usuario demo del sandbox.
27
+
28
+ > El cliente mantiene compatibilidad con las variables antiguas `SAAMFI_URL`, `SAAMFI_SYSTEM_ID` y `SAAMFI_INST_ID`.
29
+
30
+ ---
31
+
32
+ ## Quickstart
33
+
34
+ ```python
35
+ from saamfi_sdk import SaamfiClient
36
+
37
+ client = SaamfiClient() # Usa SAAMFI_BASE_URL y SAAMFI_SYS_ID desde el entorno
38
+
39
+ response = client.login("usuario@example.com", "clave-segura")
40
+ if response:
41
+ print(f"Token: {response.access_token}")
42
+ token_info = client.validate_token(response.access_token)
43
+ print(f"Roles: {token_info.roles}")
44
+ else:
45
+ print("Credenciales invalidas")
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Sandbox local con docker compose
51
+
52
+ 1. Levanta el entorno local de Saamfi con `docker compose` (puerto `9091` según la configuración compartida).
53
+ 2. Crea un archivo `.env` junto al proyecto del SDK con las variables:
54
+ ```
55
+ SAAMFI_BASE_URL=http://localhost:9091/iaslab/saamfiapi
56
+ SAAMFI_SYS_ID=8
57
+ SAAMFI_CLIENT_ID=8
58
+ SAAMFI_CLIENT_SECRET=qYr6-CxZP9t4vN2eFM1sR4gL
59
+ SAAMFI_TENANT_ID=1
60
+ SAAMFI_TEST_USERNAME=testuser
61
+ SAAMFI_TEST_PASSWORD=password123
62
+ ```
63
+ 3. Ejecuta el script de ejemplo:
64
+ ```bash
65
+ python examples/sandbox_demo.py
66
+ ```
67
+ Verás el flujo completo: descarga de clave pública, descubrimiento de sistemas/instituciones, autenticación del usuario demo, validación del JWT y consultas protegidas.
68
+
69
+ > Consulta los logs del backend en `saamfi-rest/logs/saamfi.log` o mediante `GET /logs/` (requiere rol `Query-server-logs`) para corroborar las operaciones.
70
+
71
+ ---
72
+
73
+ ## Ejemplos por funcionalidad
74
+
75
+ Cada metodo del cliente refleja una operacion del servicio Saamfi. Los siguientes fragmentos muestran el flujo completo con un token valido (`token`):
76
+
77
+ - **Obtener llave publica**
78
+ ```python
79
+ public_key = client.get_public_key()
80
+ ```
81
+
82
+ - **Autenticar usuario**
83
+ ```python
84
+ login = client.login("usuario@example.com", "clave")
85
+ ```
86
+
87
+ - **Validar token y extraer datos**
88
+ ```python
89
+ token_info = client.validate_token(token)
90
+ print(token_info.username, token_info.roles)
91
+ ```
92
+
93
+ - **Roles desde un JWT**
94
+ ```python
95
+ roles = client.get_roles_from_jwt(token)
96
+ ```
97
+
98
+ - **Informacion detallada de usuario**
99
+ ```python
100
+ user = client.get_user_info(token, user_id=12345)
101
+ ```
102
+
103
+ - **Buscar usuario por username**
104
+ ```python
105
+ user = client.get_user_by_username(token, "john.doe")
106
+ ```
107
+
108
+ - **Buscar usuarios por documentos**
109
+ ```python
110
+ users = client.get_users_by_document(token, ["100200300", "999888777"])
111
+ ```
112
+
113
+ - **Obtener usuarios por lista de IDs**
114
+ ```python
115
+ users_json = client.get_users_from_list(token, [1, 2, 3])
116
+ ```
117
+
118
+ - **Busqueda generica por parametro y valor**
119
+ ```python
120
+ result_json = client.get_users_by_param_and_value(token, "email", "example.com")
121
+ ```
122
+
123
+ - **Consultar institucion por NIT**
124
+ ```python
125
+ institution_json = client.get_institution_by_nit(token, "900123456-7")
126
+ ```
127
+
128
+ - **Consultar instituciones por IDs**
129
+ ```python
130
+ institutions_json = client.get_institutions_by_ids(token, [10, 20, 30])
131
+ ```
132
+
133
+ - **Listado público de sistemas e instituciones**
134
+ ```python
135
+ systems = client.list_public_systems()
136
+ institutions = client.list_public_institutions()
137
+ ```
138
+
139
+ - **Parámetros de institución**
140
+ ```python
141
+ params = client.get_institution_params(token) # Usa SAAMFI_TENANT_ID por defecto
142
+ ```
143
+
144
+ - **Roles configurados para un sistema**
145
+ ```python
146
+ roles = client.get_system_roles(token) # Usa SAAMFI_SYS_ID por defecto
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Referencia de API
152
+
153
+ ### Clases principales
154
+
155
+ | Clase | Descripcion |
156
+ | ----- | ----------- |
157
+ | `SaamfiClient` | Cliente principal; gestiona autenticacion, validacion y consultas. |
158
+ | `LoginBody` | Modelo para solicitudes de login. |
159
+ | `LoginResponse` | Respuesta de autenticacion exitosa. |
160
+ | `UserInfo` | Informacion detallada de usuario. |
161
+ | `UserDetailToken` | Datos extraidos de un JWT validado. |
162
+
163
+ ### Metodos clave de `SaamfiClient`
164
+
165
+ | Metodo | Entrada | Salida | Nota |
166
+ | ------ | ------- | ------ | ---- |
167
+ | `get_public_key()` | - | `RSAPublicKey` | Obtiene y cachea la llave publica. |
168
+ | `login(username, password)` | `str`, `str` | `LoginResponse | None` | Autentica usuario. |
169
+ | `get_roles_from_jwt(auth_token)` | `str` | `List[str]` | Extrae claim `role`. |
170
+ | `validate_token(auth_token)` | `str` | `UserDetailToken` | Valida firma y claims. |
171
+ | `get_user_info(auth_token, user_id)` | `str`, `int` | `UserInfo | None` | Consulta usuario por ID. |
172
+ | `get_user_by_username(auth_token, username)` | `str`, `str` | `dict | None` | Consulta POST por username. |
173
+ | `get_users_by_document(auth_token, user_documents)` | `str`, `List[str]` | `List[dict]` | Busca por multiples documentos. |
174
+ | `get_users_from_list(auth_token, user_ids)` | `str`, `List[int]` | `str | None` | JSON con usuarios por ID. |
175
+ | `get_users_by_param_and_value(auth_token, param, value)` | `str`, `str`, `str` | `str | None` | Filtro generico usando query string. |
176
+ | `get_institution_by_nit(auth_token, nit)` | `str`, `str` | `str | None` | Consulta institucion por NIT. |
177
+ | `get_institutions_by_ids(auth_token, institution_ids)` | `str`, `List[int]` | `str | None` | Consulta masiva por IDs. |
178
+ | `list_public_institutions()` | - | `List[dict] | None` | Descubrimiento de instituciones disponibles. |
179
+ | `get_institution_params(auth_token, institution_id=None)` | `str`, `Optional[int]` | `dict | None` | Obtiene parámetros de configuración institucional. |
180
+ | `list_public_systems()` | - | `List[dict] | None` | Descubrimiento de sistemas publicados. |
181
+ | `get_system_roles(auth_token, system_id=None)` | `str`, `Optional[int]` | `List[dict] | None` | Roles disponibles para un sistema. |
182
+
183
+ > Consulta los docstrings en `saamfi_sdk/client.py` para conocer detalles, equivalencias con la version Java y ejemplos adicionales.
184
+
185
+ ---
186
+
187
+ ## Manejo de errores
188
+
189
+ Todas las excepciones del SDK heredan de `SaamfiException`:
190
+
191
+ | Excepcion | Cuándo ocurre |
192
+ | --------- | ------------- |
193
+ | `SaamfiAuthenticationError` | Credenciales invalidas o token sin permisos. |
194
+ | `SaamfiTokenValidationError` | Token expirado, mal formado o con claims faltantes. |
195
+ | `SaamfiConnectionError` | Problemas de red o respuestas no exitosas del backend. |
196
+ | `SaamfiInvalidSystemError` | El token pertenece a otro `system_id`. |
197
+ | `SaamfiUnauthorizedError` | El usuario autenticado no tiene permisos para la operacion. |
198
+ | `SaamfiNotFoundError` | El recurso solicitado no existe. |
199
+
200
+ ```python
201
+ from saamfi_sdk import SaamfiClient
202
+ from saamfi_sdk.exceptions import SaamfiConnectionError, SaamfiAuthenticationError
203
+
204
+ client = SaamfiClient()
205
+
206
+ try:
207
+ login = client.login("usuario@example.com", "clave")
208
+ except SaamfiConnectionError as exc:
209
+ print(f"No es posible comunicar con Saamfi: {exc}")
210
+ except SaamfiAuthenticationError:
211
+ print("Credenciales invalidas")
212
+ ```
213
+
214
+ ---
215
+
@@ -0,0 +1,89 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "saamfi-sdk"
7
+ version = "0.1.0"
8
+ description = "SDK de Python para conectarse a los servicios SAAMFI - Autenticacion y Autorizacion"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Universidad ICESI", email = "dev@icesi.edu.co"}
14
+ ]
15
+ keywords = ["saamfi", "authentication", "authorization", "jwt", "security", "sdk"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Security",
28
+ ]
29
+ dependencies = [
30
+ "requests>=2.31.0",
31
+ "PyJWT>=2.8.0",
32
+ "cryptography>=41.0.0",
33
+ "pydantic>=2.5.0",
34
+ "python-dotenv>=1.0.0",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest>=7.4.0",
40
+ "pytest-cov>=4.1.0",
41
+ "pytest-asyncio>=0.21.0",
42
+ "black>=23.0.0",
43
+ "flake8>=6.0.0",
44
+ "mypy>=1.5.0",
45
+ "isort>=5.12.0",
46
+ ]
47
+ fastapi = [
48
+ "fastapi>=0.104.0",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://github.com/icesi-dev/saamfi-sdk-python"
53
+ Documentation = "https://saamfi-sdk-python.readthedocs.io"
54
+ Repository = "https://github.com/icesi-dev/saamfi-sdk-python.git"
55
+ Issues = "https://github.com/icesi-dev/saamfi-sdk-python/issues"
56
+
57
+ [tool.setuptools]
58
+ include-package-data = true
59
+
60
+ [tool.setuptools.packages.find]
61
+ include = ["saamfi_sdk*"]
62
+
63
+ [tool.setuptools.package-data]
64
+ saamfi_sdk = ["py.typed"]
65
+
66
+ [tool.pytest.ini_options]
67
+ testpaths = ["tests"]
68
+ python_files = "test_*.py"
69
+ python_classes = "Test*"
70
+ python_functions = "test_*"
71
+ addopts = "-v --cov=saamfi_sdk --cov-report=term-missing"
72
+ markers = [
73
+ "integration: Tests that hit the local Saamfi sandbox (requires RUN_SAAMFI_SANDBOX_TESTS=1)",
74
+ ]
75
+
76
+ [tool.black]
77
+ line-length = 100
78
+ target-version = ['py38', 'py39', 'py310', 'py311']
79
+ include = '\.pyi?$'
80
+
81
+ [tool.isort]
82
+ profile = "black"
83
+ line_length = 100
84
+
85
+ [tool.mypy]
86
+ python_version = "3.8"
87
+ warn_return_any = true
88
+ warn_unused_configs = true
89
+ disallow_untyped_defs = true
@@ -0,0 +1,22 @@
1
+ # Include production dependencies
2
+ -r requirements.txt
3
+
4
+ # Testing
5
+ pytest>=7.4.0
6
+ pytest-cov>=4.1.0
7
+ pytest-mock>=3.12.0
8
+ pytest-asyncio>=0.21.0
9
+
10
+ # Code Quality
11
+ black>=23.11.0
12
+ flake8>=6.1.0
13
+ mypy>=1.7.0
14
+ isort>=5.12.0
15
+
16
+ # Documentation
17
+ mkdocs>=1.5.0
18
+ mkdocs-material>=9.4.0
19
+
20
+ # Development utilities
21
+ python-dotenv>=1.0.0
22
+ ipython>=8.17.0
@@ -0,0 +1,17 @@
1
+ # HTTP Client
2
+ requests>=2.31.0
3
+
4
+ # JWT Handling
5
+ PyJWT>=2.8.0
6
+
7
+ # Cryptography for RSA keys
8
+ cryptography>=41.0.0
9
+
10
+ # Data Validation
11
+ pydantic>=2.5.0
12
+
13
+ # Environment Variables
14
+ python-dotenv>=1.0.0
15
+
16
+ # Optional: FastAPI integration (peer dependency)
17
+ # fastapi>=0.104.0 # Users install this themselves
@@ -0,0 +1,49 @@
1
+ """
2
+ Saamfi SDK for Python
3
+
4
+ Python SDK to connect to SAAMFI services - Authentication and Authorization.
5
+
6
+ This SDK is equivalent to saamfi-security (Java SDK) and provides the same
7
+ functionality for systems that require integration with the Saamfi service.
8
+
9
+ Basic usage:
10
+ >>> from saamfi_sdk import SaamfiClient
11
+ >>> client = SaamfiClient("https://saamfi.example.com", system_id=123)
12
+ >>> # Client is ready for authentication and token validation
13
+
14
+ Equivalent to: co.edu.icesi.dev.saamfi.saamfisecurity (Java package)
15
+ """
16
+
17
+ __version__ = "0.1.0"
18
+
19
+ from .client import SaamfiClient
20
+ from .exceptions import (
21
+ SaamfiAuthenticationError,
22
+ SaamfiConnectionError,
23
+ SaamfiException,
24
+ SaamfiInvalidSystemError,
25
+ SaamfiNotFoundError,
26
+ SaamfiTokenValidationError,
27
+ SaamfiUnauthorizedError,
28
+ )
29
+ from .models import LoginBody, LoginResponse, UserDetailToken, UserInfo
30
+
31
+ __all__ = [
32
+ # Main client
33
+ "SaamfiClient",
34
+ # Models
35
+ "LoginBody",
36
+ "LoginResponse",
37
+ "UserInfo",
38
+ "UserDetailToken",
39
+ # Exceptions
40
+ "SaamfiException",
41
+ "SaamfiAuthenticationError",
42
+ "SaamfiTokenValidationError",
43
+ "SaamfiConnectionError",
44
+ "SaamfiInvalidSystemError",
45
+ "SaamfiUnauthorizedError",
46
+ "SaamfiNotFoundError",
47
+ # Metadata
48
+ "__version__",
49
+ ]