How can Python's zeep module work against an API manager? - soap

I've used zeep against a SOAP-service, and it works perfectly. However, when this service is placed behind Gravitee API Manager, I'm unable to get it to work any longer, just get a 404 response.
Here's my code :
from zeep import Client, Settings
import base64,sys, logging, traceback
from requests import Session
from zeep.transports import Transport
import requests
from lxml import etree
wsdl= 'https://link_to_service_on_gravitee'
session = Session()
session.verify = False
session.headers['Api-Key']= 'xxxxx'
transport = Transport(session=session)
settings = Settings(raw_response=True, strict=False, xml_huge_tree=True)
client = Client(wsdl, transport=transport, settings=settings)
data = []
data.append(
{'ServerProcessId': 'GL07',
'OrderNumber': 1}
)
cdata = []
cdata.append(
{'Username': 'xxx',
'Client': 'yyy',
'Password': 'zzz'}
)
node = client.create_message(client.service, 'GetResult',input=data, credentials=cdata)
print('*** SOAP Message')
print(etree.tostring(node))
print('*** End SOAP Message')
response = requests.Response()
try:
response = client.service.GetResult(input=data, credentials=cdata)
print(response)
except Exception as e:
print(response.headers)
logging.error(traceback.format_exc())
When I test the message generated by Python (etree.tostring(node)) in SOAPUI, it works correctly. Also, if I alter the api-key, I get an error about authentication problems, so Gravitee seems to accept the key from my code.
But the response I get, with correct api-key, is always [404].
Got it to work when I downloaded the wsdl to a local file, but don't want to do this for every wsdl.
Any ideas ?

There are multiple reasons for getting a 404 from Gravitee:
* Did you create an API
* Did you create a simple plan for this API
* Did you deploy the API to the gateway.
Once all those steps are done, you should be able to consume your API.
Hope it helps,
Regards,

Related

Strange issue with Vertx Http request

I configured an HTTPS website on AWS, which allows visiting from a white list of IPs.
My local machine runs with a VPN connection, which is in the white list.
I could visit the website from web browser or by the java.net.http package with the below code:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://mywebsite/route"))
.GET() // GET is default
.build();
HttpResponse<Void> response = client.send(request,
HttpResponse.BodyHandlers.discarding());
But if I replaced the code with a Vertx implementation from io.vertx.ext.web.client package, I got a 403 forbidden response from the same website.
WebClientOptions options = new WebClientOptions().setTryUseCompression(true).setTrustAll(true);
HttpRequest<Buffer> request = WebClient.create(vertx, options)
.getAbs("https://mywebsite/route")
.ssl(true).putHeaders(headers);
request.send(asyncResult -> {
if (asyncResult.succeeded()) {
HttpResponse response = asyncResult.result();
}
});
Does anyone have an idea why the Vertx implementation is rejected?
Finally got the root cause. I started a local server that accepts the testing request and forwards it to the server on AWS. The testing client sent the request to localhost and thus "Host=localhost:8080/..." is in the request header. In the Vert.X implementation, a new header entry "Host=localhost:443/..." is wrongly put into the request headers. I haven't debug the Vert.X implementation so I have no idea why it behaviors as this. But then the AWS firewall rejected the request with a rule that a request could not come from localhost.

Unable to access Rest URL using scalaj-Http client with SSL certificates(JKS File)

I am new to Scala. I am trying to access REST API URl and trying to get json data from there using Scalaj-Http with Spark framework in local vm(Intellij). But with the following Code I am always getting Http error code 401 from code and the server log is responding with "new ssl session,TLS V1.2 No Client Cert.
The jks file that I am using seems ok with proper SSL Handshake and its installed on server side.
val url = "https://abcdef:1234/api/v1/get?q=abc"
val alias ="xxxxxx-1234 yyyyy"
val sslFactory = SSLFactory.builder()
.withIdentityMaterial("abc.jks","pass".tocharArray)
.withTrustMaterial("abc.jks","pass".tocharArray)
.withClientIdentityRoute(alias,url)
.build()
val optn = HttpOptions.sslSocketFactory(sslfactory.getSslSocketfactory)
val res = Http(url) //Here getting 401 res.code
.option(optn)
.option(HttpOptions.allowUnsafeURL)
.asString
Tried everything but unable to solve. Kindly help please
I got the code working as I have to discard this option option(HttpOptions.allowUnsafe
URL)
Thanks

Getting connection timeout error while calling get access token Microsoft Graph API through REST POST call

I am trying to get access token from https://login.microsoftonline.com/{tenentname}/oauth2/v2.0/token endpoints though HttpClient post request. Applied required 4 parameters/headers with the same.
But I am getting connection timed out. Connection will be retried using another IP address (after trying with 7 different IP address) getting Shutdown connection error. Connection discarded.
Please find below code snippet.
HttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
HttpPost post = new HttpPost("https://login.microsoftonline.com/{tenentname}/oauth2/v2.0/token");
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("grant_type", "client_credentials"));
urlParameters.add(new BasicNameValuePair("client_id", {id_value}));
urlParameters.add(new BasicNameValuePair("client_secret", {secret_value}));
urlParameters.add(new BasicNameValuePair("scope", "https://graph.microsoft.com/.default"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
post.setHeader("Content-type", "application/x-www-form-urlencoded");
ClosableHttpClinet httpClient = HttpClients.custom().setConnectionManager(poolingConnManager).build();
ClosableHttpResponse response = httpClinet.execute(post);
System.out.println(EntityUtils.toString(response.getEntity()));
Same its worked with Postman without any proxy setting, I am getting proper response in Postman.
Please assist on the same.
Instead of using HTTPClient, i tried with Microsoft Graph Client (you can download from NuGet) and it worked for me. So i would suggest you to follow the steps.
Install the SDK
Configure the GraphClient
Make the call.
Also with specific to ivy dependency, here's the related thread.

Testing connectivity using API key in the header using Flask and PyMongo

My server has to ensure the connectivity by receiving the request with API Key in the header from the client. I am finding it difficult to incorporate this using Flask decorator.
We provided API key to our Client which will be used to receiving the request.
When every request is made, we check and authenticate the Client for posting updates into our database.
The Swagger API definition has the parameter of API key located in Header which needs to be implemented using the Flask Decorator and corresponding function.
I have written the following Flask app code. And when It comes to receiving the API in the header, I am failing to rectify this server Error.
from flask import Flask, render_template, url_for, request, session, redirect,jsonify
from flask_pymongo import PyMongo
import json
from bson.json_util import dumps
import bcrypt
import os
from binascii import hexlify
app = Flask(__name__)
app.config['MONGO_DBNAME'] = 'demo'
app.config['MONGO_URI'] = 'mongodb://xxxx:xxxx#xxxxxxx.mlab.com:57158/demo'
mongo = PyMongo(app)
#app.route('/addapi')
def addapi():
users = mongo.db.users
api_key=users.insert({"name":"apikey","X-API-Key":"69222c9b-7858-4eef-a218-039c8cd2bc6e"})
return 'API Key stored'
#app.route('/test/<string:apikey_given_by_user_in_the_header>',methods=['GET'])
"""I have a doubt in the above line that How Can I receive the API Key in the header and check if that is available in my database. This is for testing the connectivity using the Valid API Key."""
def test(apikey_given_by_user_in_the_header):
users=mongo.db.users
api_record=users.find_one({'name':"apikey"})
actual_API_key=api_record['X-API-Key']
if actual_API_key==apikey_given_by_user_in_the_header
return "API is available"
return "Invalid API Key"
The Swagger API definition for Parameter is as below:
"parameters": [
{
"name": "X-API-Key",
"in": "header",
"required": true,
"type": "string"
},
Can You kindly advise How can I incorporate this API key authentication where the Client will have to input the API key based upon which my server needs to check and authenticate? Thanks.
To access incoming request data, you can use the global request object.
when client send a request with header which you need, you can access incoming request header request.headers, header is dictionary like object:
from flask import request
#app.route('/api')
def home():
key = request.headers.get('API-Key')
print(key)
return 'Got %s key'%key
To test with curl or httpie
$ http get localhost:port/api API-Key:key-goes-here12458
$ curl -H "API-Key:key-goes-here12458" localhost:port/api

Rest assured with digest auth

I have a working spring-mvc application with rest services and some rest-assured tests which are fine :
#Test
public void createFoobarFromScratchReturns201(){
expect().statusCode(201).given()
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
}
=> OK
Then I implemented a digest authentication. Everything is working well, now I have to log in to use my services :
curl http://localhost:8089/foo/bar
=> HTTP ERROR 401, Full authentication is required to access this resource
curl http://localhost:8089/foo/bar --digest -u user_test:password
=> HTTP 201, CREATED
But when I try to upgrade my tests with the most obvious function, I still have a 401 error :
#Test
public void createFoobarFromScratchReturns201(){
expect().statusCode(201).given()
.auth().digest("user_test", "password") // Digest added here
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
}
=> Expected status code <201> doesn't match actual status code <401>
I found some clues with the preemptive() function, but it seems to be only implemented for basic :
// Returns an AuthenticatedScheme and stores it into the general configuration
RestAssured.authentication = preemptive().basic("user_test", "password");
// Try a similar thing, but it didn't work :
RestAssured.authentication = RestAssured.digest("user_test", "password");
Currently, I am trying to achieve two things :
I need to upgrade a couple of my tests to support digest
I need to amend the #Before of the rest of my tests suites (whose are not related to auth issues), to be already logged in.
Any ideas or documentation ?
Try enabling support for cookies in the HTTP client embedded inside Rest Assured with:
RestAssuredConfig config = new RestAssuredConfig().httpClient(new HttpClientConfig().setParam(ClientPNames.COOKIE_POLICY, CookiePolicy.BEST_MATCH));
expect().statusCode(201).given()
.auth().digest("user_test", "password") // Digest added here
.config(config)
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
The HTTP client (and therefore Rest Assured) supports digest authentication and the configuration of RestAssured using the digest method works well.