Enviar archivos de AL11 a un servidor SFTP con SAP Cloud Integration
Una guía completa — probar la conexión SSH, añadir la clave de host del socio a known_hosts, construir el iFlow y enviar los archivos de AL11 con un pequeño report ABAP.
Un requisito muy habitual: S/4HANA escribe un archivo en el servidor de aplicaciones (AL11) — facturas, pagos, listas de stock — y un socio lo quiere en su servidor SFTP. En este artículo montamos ese flujo con SAP Cloud Integration (parte de Integration Suite), desde la primera prueba de conexión hasta que el archivo llega al otro lado.
La idea
Cloud Integration se ejecuta en la nube y no ve el sistema de archivos de tu servidor de aplicaciones on-premise. Por eso invertimos el sentido:
- Un pequeño report ABAP lee el archivo de AL11 y lo envía al endpoint HTTPS de un iFlow.
- El iFlow lo escribe en el servidor del socio con el adaptador SFTP receiver.
- El report mueve el archivo original a una carpeta de archivo.
Otra opción es un adaptador SFTP sender que consulta un servidor SFTP de tu red a través del Cloud Connector. Para eso necesitas un servidor SFTP propio; el enfoque anterior no necesita nada adicional.
Qué pedirle al socio
| Información | Ejemplo |
|---|---|
| Host y puerto | sftp.partner-example.com:22 |
| Usuario | s4_upload |
| Autenticación | Contraseña o clave pública |
| Directorio destino | /inbound/ |
| ¿Lista blanca de IP? | Si es así, envíale las IP de salida de tu región de Cloud Integration |
1. Probar la conexión y obtener la clave de host
Abre Monitor → Integrations and APIs → Manage Security → Connectivity Tests y ve a la pestaña SSH.
- Host / Port: el servidor del socio
- Proxy Type:
Internet - Authentication:
Noneen el primer intento - Deja Check Host Key sin marcar — aún no conocemos la clave
Pulsa Send. Si el servidor responde, verás su clave de host. Pulsa Copy Host Key.
Si la prueba termina en timeout, casi siempre es un firewall: el socio todavía no ha permitido tus IP de Cloud Integration.
2. Añadir la clave de host a known_hosts
El adaptador SFTP solo se conecta a servidores que conoce. Esa lista es un material de seguridad llamado known_hosts. Esta comprobación es la que te protege de que alguien se haga pasar por el servidor del socio.
Ve a Manage Security → Security Material:
- Si
known_hostsya existe, descárgalo primero y añade la nueva línea al final. Nunca subas un archivo que solo contenga la clave nueva: se perderían los hosts de todas las demás integraciones. - Después elige Upload → Known Hosts (SSH), mantén el nombre
known_hostsy despliega.
# one line per host: <host> <key type> <base64 public key>
sftp.old-partner.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7v...
sftp.partner-example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM8wq2xYkRb4Tq3Vn0e7HhGfPz1cL5uXo9Ks2dWm4AaQe
3. Guardar las credenciales
- Contraseña: Security Material → Create → User Credentials, por ejemplo
SFTP_PARTNER_USER. - Clave pública: Keystore → Create → SSH Key. Descarga la clave OpenSSH pública y envíasela al socio; la clave privada nunca sale del tenant. En el adaptador la indicas con Private Key Alias.
4. Probar de nuevo — esta vez completo
De vuelta en la prueba SSH:
- Authentication:
User CredentialsconSFTP_PARTNER_USER(oPublic Key) - Check Host Key: ✓
- Check Directory Access: ✓ con
/inbound/
Cuando esta prueba sale en verde, la parte de Cloud Integration está lista. Cualquier error posterior estará en el iFlow o en ABAP, lo que facilita mucho el análisis.
5. Construir el iFlow
Adaptador HTTPS sender
- Address:
/al11/sftp-out - User Role:
ESBMessaging.send - CSRF Protected: sin marcar — nuestro report ABAP no obtiene token
En la Runtime Configuration del iFlow, añade FileName en Allowed Header(s). Si no, Cloud Integration descarta la cabecera y se pierde el nombre del archivo.
Content Modifier — definir el nombre del archivo destino:
Message Header
Name: TargetFile
Source Type: Expression
Source Value: ${header.FileName}
Optional – add a timestamp to avoid overwriting:
Source Value: ${date:now:yyyyMMdd_HHmmss}_${header.FileName}
Adaptador SFTP receiver
| Campo | Valor |
|---|---|
| Address | sftp.partner-example.com:22 |
| Proxy Type | Internet |
| Authentication | User Name/Password |
| Credential Name | SFTP_PARTNER_USER |
| Directory | /inbound/ |
| File Name | ${header.TargetFile} |
| Handling for Existing Files | Fail — más seguro que sobrescribir |
Despliega el iFlow y copia su endpoint desde Monitor → Manage Integration Content.
6. El lado ABAP: SM59 y el report
Crea en SM59 un destino HTTP de tipo G:
- Target Host: el host runtime de tu tenant (
...-rt.cfapps.<región>.hana.ondemand.com) - Port:
443, SSL: activo - Path Prefix:
/http/al11/sftp-out - Logon: autenticación básica con
clientid/clientsecretde una clave de servicio de Process Integration Runtime (planintegration-flow), o un certificado de cliente
Importa la cadena de certificados del servidor en STRUST (identidad SSL cliente) para que funcione el handshake TLS.
Los archivos pendientes en AL11:
Y el report:
REPORT zal11_to_cpi_sftp.
" Reads a file from the application server (AL11), posts it to a
" Cloud Integration iFlow and moves it to an archive folder.
" Classic ABAP (on-premise): OPEN DATASET is not available in ABAP Cloud.
PARAMETERS: p_dir TYPE c LENGTH 200 LOWER CASE DEFAULT '/interface/sftp_out/',
p_file TYPE c LENGTH 120 LOWER CASE OBLIGATORY,
p_arch TYPE c LENGTH 200 LOWER CASE DEFAULT '/interface/sftp_out/archive/'.
CONSTANTS c_destination TYPE rfcdest VALUE 'ZCPI_SFTP_OUT'.
START-OF-SELECTION.
DATA(path) = |{ p_dir }{ p_file }|.
DATA(archive) = |{ p_arch }{ p_file }|.
DATA content TYPE xstring.
" 1. Read the file from AL11
TRY.
OPEN DATASET path FOR INPUT IN BINARY MODE.
IF sy-subrc <> 0.
MESSAGE |File { path } cannot be opened| TYPE 'E'.
ENDIF.
READ DATASET path INTO content.
CLOSE DATASET path.
CATCH cx_sy_file_access_error INTO DATA(file_error).
MESSAGE file_error->get_text( ) TYPE 'E'.
ENDTRY.
" 2. Post it to the iFlow (SM59 destination of type G)
DATA client TYPE REF TO if_http_client.
cl_http_client=>create_by_destination(
EXPORTING destination = c_destination
IMPORTING client = client
EXCEPTIONS OTHERS = 1 ).
IF sy-subrc <> 0.
MESSAGE |Destination { c_destination } cannot be used (SM59)| TYPE 'E'.
ENDIF.
client->request->set_method( if_http_request=>co_request_method_post ).
client->request->set_content_type( 'application/octet-stream' ).
client->request->set_header_field( name = 'FileName' value = CONV #( p_file ) ).
client->request->set_data( content ).
client->send( EXCEPTIONS OTHERS = 1 ).
IF sy-subrc = 0.
client->receive( EXCEPTIONS OTHERS = 1 ).
ENDIF.
IF sy-subrc <> 0.
DATA error_text TYPE string.
client->get_last_error( IMPORTING message = error_text ).
MESSAGE error_text TYPE 'E'.
ENDIF.
DATA status TYPE i.
DATA reason TYPE string.
client->response->get_status( IMPORTING code = status reason = reason ).
client->close( ).
IF status <> 200.
MESSAGE |Cloud Integration answered { status } { reason }| TYPE 'E'.
ENDIF.
" 3. Archive: write a copy, then delete the original
OPEN DATASET archive FOR OUTPUT IN BINARY MODE.
TRANSFER content TO archive.
CLOSE DATASET archive.
DELETE DATASET path.
MESSAGE |{ p_file } sent to the SFTP server and archived| TYPE 'S'.
Para producción, ten en cuenta:
- Nombres de archivo lógicos (transacción
FILE) en lugar de rutas libres, y una comprobación de autorización sobreS_DATASET. - Un job en segundo plano (
SM36) que recorra todo el directorio en lugar de un archivo por ejecución.
7. Prueba de extremo a extremo
- Ejecuta el report con un nombre de archivo de AL11.
- En Monitor → Message Processing el mensaje debe aparecer como Completed.
- El archivo está en
/inbound/del socio y en AL11 se ha movido aarchive/.
Solución de problemas
| Síntoma | Causa probable | Solución |
|---|---|---|
Auth fail / clave de host rechazada |
Clave ausente o cambiada | Paso 2 — actualizar known_hosts |
| Timeout de conexión | Firewall / lista blanca | El socio permite tus IP de CPI |
No such file / permiso denegado |
Directorio o permisos incorrectos | Prueba con Check Directory Access |
| HTTP 401 / 403 en ABAP | Client ID/secret o rol incorrecto | Revisar la clave de servicio y ESBMessaging.send |
| HTTP 403 con mensaje CSRF | Protección CSRF activa | Desmarcar CSRF Protected |
| El archivo llega con otro nombre | Cabecera FileName descartada |
Añadirla en Allowed Header(s) |
| «El archivo ya existe» | Handling for Existing Files = Fail | Añadir una marca de tiempo al nombre |
Lo bueno de este montaje es que cada pieza se prueba por separado: la conexión SSH, el iFlow y el report ABAP. Cuando algo falla, sabes enseguida dónde mirar.
Comentarios