Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Authenticated API not correctly attaching self-signed certificates #21608

Closed
1 task done
felix-appsmith opened this issue Mar 20, 2023 · 2 comments
Closed
1 task done
Assignees
Labels
Backend This marks the issue or pull request to reference server code BE Coders Pod Issues related to users writing code to fetch and update data Bug Something isn't working Integrations Pod Issues related to a specific integration Medium Issues that frustrate users due to poor UX OAuth OAuth related bugs or features

Comments

@felix-appsmith
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Description

Currently, when we have an API that requires authentication through self-signed certificates, even if we attach our PEM file, Appsmith is not able to read it and displays the following error:

org.springframework.web.reactive.function.client.WebClientRequestException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.

Example video:

certificates.mp4

Steps To Reproduce

  1. Connect to a self-signed certificate API. You can use this Python script to generate the server with its PEM certificates.
   
from flask import Flask, request, jsonify
import ssl
import os
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import serialization
from datetime import datetime, timedelta
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend

app = Flask(__name__)

cert_path = os.path.join(os.path.dirname(__file__), 'cert.pem')
key_path = os.path.join(os.path.dirname(__file__), 'key.pem')
if not os.path.exists(cert_path) or not os.path.exists(key_path):
   print("Generando certificado y clave...")
   
   private_key = rsa.generate_private_key(
       public_exponent=65537,
       key_size=2048
   )

   subject = issuer = x509.Name([
       x509.NameAttribute(NameOID.COMMON_NAME, u"localhost")
   ])
   cert = x509.CertificateBuilder().subject_name(
       subject
   ).issuer_name(
       issuer
   ).public_key(
       private_key.public_key()
   ).serial_number(
       x509.random_serial_number()
   ).not_valid_before(
       datetime.utcnow()
   ).not_valid_after(
       datetime.utcnow() + timedelta(days=365)
   ).add_extension(
       x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
       critical=False,
   ).sign(private_key, hashes.SHA256(), default_backend())

   with open(cert_path, 'wb') as f:
       f.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
   with open(key_path, 'wb') as f:
       f.write(private_key.private_bytes(
           encoding=serialization.Encoding.PEM,
           format=serialization.PrivateFormat.TraditionalOpenSSL,
           encryption_algorithm=serialization.NoEncryption()
       ))
   print("Certificate and key generated at the following location:")
   print(cert_path)
   print(key_path)

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(cert_path, key_path)

users = [
   {"username": "user1", "password": "pass1"},
   {"username": "user2", "password": "pass2"}
]

def authenticate(username, password):
   for user in users:
       if user["username"] == username and user["password"] == password:
           return True
   return False

@app.route('/protected')
def protected():
   auth = request.authorization
   if not auth or not authenticate(auth.username, auth.password):
       return jsonify({'error': 'Unauthorized access'}), 401
   return jsonify({'message': 'Welcome to the protected area!'})

if __name__ == '__main__':
   app.run(ssl_context=context)

Note: install these libraries: pip install flask && pip install cryptography
2. Run this curl command from the directory where you executed the Python code to verify a successful connection.
3. Expose port 5000 through Ngrok to connect to it from Appsmith.
4. Create your data source in Appsmith with an authenticated API.
5. In the URL field, put the URL that Ngrok gave you, plus this endpoint: /protected.
6. Attach the cert.pem certificate generated by the Python code.

Public Sample App

No response

Environment

Production

Issue video log

No response

Version

Appsmith v1.9.12-SNAPSHOT/ Cloud Appsmith Community v1.9.12

@felix-appsmith felix-appsmith added Bug Something isn't working Needs Triaging Needs attention from maintainers to triage labels Mar 20, 2023
@pranavkanade pranavkanade added the OAuth OAuth related bugs or features label Mar 29, 2023
@github-actions github-actions bot added Integrations Pod Issues related to a specific integration BE Coders Pod Issues related to users writing code to fetch and update data labels Mar 29, 2023
@Rytorcen
Copy link

Is there any option to disable SSL check within appsmith?

Can confirm the error.
System: self-hosted appsmith on docker tested with self-hosted API (self-signed cert)
API is fully functioning with Python or Postman.

Execution failed with status PE-RST-5000 -org.springframework.web.reactive.function.client.WebClientRequestException

TEST via CLI

docker-compose exec appsmith curl -v https://X.X.X.X
*   Trying X.X.X:X:443...
* TCP_NODELAY set
* Connected to X.X.X.X (X.X.X.X) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to X.X.X.X:443
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to X.X.X.X:443

DOCKER LOG

[2023-03-30 12:09:01,778] userEmail=XX, sessionId=723b199e-e188-4eec-af9b-0282da2c6ded, thread=nioEventLoopGroup-3-6, requestId=52a88b1c-d046-45b9-b499-c997af47a74f - Datasource context doesn't exist. Creating connection.
2023-03-30 14:09:01 backend stdout | 
2023-03-30 14:09:01 backend stdout | [2023-03-30 12:09:01,856]  - [28661514, L:/172.19.0.2:38894 ! R:omitted/omitted:443] The connection observed an error
2023-03-30 14:09:01 backend stdout | java.nio.channels.ClosedChannelException: null
2023-03-30 14:09:01 backend stdout |    at io.netty.handler.ssl.SslHandler.channelInactive(SslHandler.java:1065)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:305)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:274)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:301)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.AbstractChannel$AbstractUnsafe$7.run(AbstractChannel.java:813)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
2023-03-30 14:09:01 backend stdout |    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:403)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
2023-03-30 14:09:01 backend stdout |    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
2023-03-30 14:09:01 backend stdout |    at java.base/java.lang.Thread.run(Thread.java:833)

@sribalajig sribalajig added Medium Issues that frustrate users due to poor UX and removed Needs Triaging Needs attention from maintainers to triage labels Apr 6, 2023
@rohan-arthur rohan-arthur added the Backend This marks the issue or pull request to reference server code label May 1, 2023
@sumitsum
Copy link
Contributor

This issue does not seem valid with v1.9.19. To verify I have followed all the steps as provided in the description, except Appsmith instance was running on my local. I think there is a minor error in the way the test is described. Apart from attaching the self signed certificate we also need to provide the username and password info via the REST API header which turns out to be Authorization: Basic dXNlcjE6cGFzczE= , e.g. the curl request would look like:

curl --cacert cert.pem --header "Authorization: Basic dXNlcjE6cGFzczE=" https://localhost:5000/protected 

Also, as per my understanding, we cannot use ngrok with the python server since ngrok would expose a different endpoint for which we don't have the self signed certificate (the Python script provided creates the self signed certificate for the localhost endpoint).

The same works with Appsmith as well:
Screenshot 2023-05-15 at 4 55 19 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend This marks the issue or pull request to reference server code BE Coders Pod Issues related to users writing code to fetch and update data Bug Something isn't working Integrations Pod Issues related to a specific integration Medium Issues that frustrate users due to poor UX OAuth OAuth related bugs or features
Projects
None yet
Development

No branches or pull requests

7 participants