Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The specifics of adding a header to an api call with a swagger codegen client in python are unclear

Point out the right document, tutorial, example, or provide one, showing how to add a specific authentication token to a specific header in the Swagger generated API client in Python?

Here's what I've tried:
My API call works just fine with the right curl command:

curl -v -H 'X-CAG-Authorization: AG_CONSUMER_TOKEN access-key=31337-70k3n' \
     'https://api.company.net/api/v1/user/detail?user=1'

*   Trying 10.10.1.10...
* Connected to api.company.net (10.10.1.10) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: *.company.net
* Server certificate: COMODO RSA Organization Validation Secure Server CA
* Server certificate: COMODO RSA Certification Authority
> GET /api/v1/user/detail?user=1 HTTP/1.1
> Host: api.company.net
> User-Agent: curl/7.49.1
> Accept: */*
> X-CAG-Authorization: AG_CONSUMER_TOKEN access-key=31337-70k3n
> 
< HTTP/1.1 200 OK
< Server: openresty
< Date: Thu, 22 Dec 2016 19:46:05 GMT
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Connection: close
< Vary: Accept-Encoding
< Vary: Accept-Encoding
< X-UA-Compatible: IE=edge
< 
{"successful":true,"message":"SUCCESS","body":{"…

However, when I try the same basic request in my Python (2.7.12) client I get an authorization failure, despite confirming that the token makes it into the header about to be used. More details on the right way to use the client OR on how to get more details of the exact request and response would be appreciated.

/Users/me/VEnvs/sku-grade/bin/python /Users/me/prj/code/python_client/api_example.py
HEADERS:
{'X-CAG-Authorization': 'AG_CONSUMER_TOKEN access-key=31337-70k3n', 'User-Agent': 'Swagger-Codegen/1.0.0/python'}
Exception when calling SupplierApi->get_api_v1_user_details: (401)
Reason: Unauthorized
HTTP response headers: HTTPHeaderDict({'Date': 'Thu, 22 Dec 2016 21:09:30 GMT', 'Content-Length': '636', 'Content-Type': 'application/json; charset=UTF-8', 'Connection': 'keep-alive', 'Server': 'nginx'})
HTTP response body: {
  "code" : "PRECONDITION_FAILED",
  "type" : "UnauthorizedApiDeniedException",
  "message" : "Target API(/api/v1/user/details) is not available, you have to get a grant in advance.",
  "messages" : {…

Here's a swagger api spec: swagger.yaml

---
swagger: "2.0"
info:
  description: "API"
  version: "TEMPORARY"
  title: "User Details"
  termsOfService: "http://wiki.company.net/tos"
  contact:
    name: "…"
  license:
    name: "…"
host: "api.company.net"
basePath: "/api/v1"
tags:
- name: "supplier"
  description: "Supplier"
schemes:
- "https"
produces:
- "application/json"
paths:
  /user/details:
    get:
      tags:
      - "supplier"
      summary: "userDetails"
      operationId: "getApiV1UserDetails"
      consumes:
      - "application/json"
      produces:
      - "application/json;charset=utf-8"
      parameters:
      - name: "user"
        in: "query"
        description: "user id"
        required: true
        type: "integer"
        format: "Long"
      responses:
        200:
          description: "OK"
          schema:
            $ref: "#/definitions/SupplierResponseOfUserDetailsDto"
        401:
          description: "Unauthorized"
        403:
          description: "Forbidden"
        404:
          description: "Not Found"
definitions:
  SupplierResponseOfUserDetailsDto:
    type: "object"
    properties:
      body:
        $ref: "#/definitions/UserDetailsDto"
      message:
        type: "string"
      successful:
        type: "boolean"
  UserDetailsDto:
    type: "object"
    properties:
      name:
        type: "string"

The swagger-codegen was run from http://editor.swagger.io/ and I followed the api example trying to add in the extra header: api_example.py

from __future__ import print_function
import time
import swagger_client
from swagger_client import ApiClient
from swagger_client import Configuration
from swagger_client.rest import ApiException
from pprint import pprint

# Setup the authentication token header
conf = Configuration()
conf.api_key_prefix = {"teamname": "AG_CONSUMER_TOKEN"}
conf.api_key = {
    "teamname": "access-key=31337-70k3n"
}
conf.api_client = ApiClient(None, "X-CAG-Authorization",
                            conf.get_api_key_with_prefix("teamname"))

# create an instance of the API class
api_instance = swagger_client.SupplierApi()
user = 1
try:
    api_response = api_instance.get_api_v1_user_details(user)
    pprint(api_response)
except ApiException as e:
    print("Exception when calling "
          "SupplierApi->get_api_v1_user_details: %s\n" % e)

By putting a print(self.api_client.default_headers) into the supplier_api.py I could see that the header did appear to be set.

{'X-CAG-Authorization': 'AG_CONSUMER_TOKEN access-key=31337-70k3n', 'User-Agent': 'Swagger-Codegen/1.0.0/python'}

So again what should I change in my example to get it to pass on the header and get authorized exactly the way a simple curl call does?

Update I've also tried defining it:

      security:
      - api_key: []
securityDefinitions:
  api_key:
    type: "apiKey"
    name: "X-CAG-Authorization"
    in: "header"

and then only setting up the key with:

swagger_client.configuration.api_key['X-CAG-Authorization'] = \
    'access-key=31337-70k3n'
swagger_client.configuration.api_key_prefix['X-CAG-Authorization'] = \
    'AG_CONSUMER_TOKEN'

But that didn't change much other than the header disappears from the default headers I was printing.

like image 485
dlamblin Avatar asked Dec 22 '16 21:12

dlamblin


1 Answers

I've tried your code example and it looks like your headers are actually passed to server.

You can confirm this by adding print headers to swagger_client/rest.py file, just before this:

r = self.pool_manager.request(method, url,
                              fields=query_params,
                              preload_content=_preload_content,
                              timeout=timeout,
                              headers=headers)

Are you sure there is no problem on server side? Maybe some headers breaking the authentication?

Does the following curl command also work?

curl -v \
 -H 'X-CAG-Authorization: AG_CONSUMER_TOKEN access-key=31337-70k3n' \
 -H 'Content-Type: application/json' \
 -H 'Accept: application/json;charset=utf-8' \
 -H 'User-Agent: Swagger-Codegen/1.0.0/python' \
 'https://api.company.net/api/v1/user/detail?user=1'

Because this should give you the exact same answer that returned to swagger, which is 401 error. If it does, you can debug from there on server side. If it doesn't, I have no idea.

like image 139
previous_developer Avatar answered Sep 18 '22 02:09

previous_developer