7

I have a django rest_framework API, Swagger and a Swagger UI. When I am not logged in I can see a very limited view of "login" and "docs". When I am logged in I can see lots of stuff.

I am trying to use the swagger-codegen to generate a client:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar \
generate -i http://127.0.0.1:8080/api/docs/ -l python -o myclient

However, it only generates a very limited client that provides the "login" and "docs" functionality.

How do I let swagger-codegen know how to login using http basic authentication, in order for it to generate a more complete client?

The docs says I should do the following, but I do not know what it expects:

    -a <authorization>, --auth <authorization>
        adds authorization headers when fetching the swagger definitions
        remotely. Pass in a URL-encoded string of name:header with a comma
        separating multiple values
tomsv
  • 7,207
  • 6
  • 55
  • 88

3 Answers3

16

Since you are using http basic authentication the command should be:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar \
generate -i http://127.0.0.1:8080/api/docs/ -l python -o myclient -a "Authorization:Basic QWxhZGRpbjpPcGVuU2VzYW1l"

Where QWxhZGRpbjpPcGVuU2VzYW1l is your username:password encoded in base64.

Here you can have a look at the code that will parse this option.

moondaisy
  • 4,303
  • 6
  • 41
  • 70
  • 2
    You can use [this site](https://www.base64encode.org) to encode the credentials using the following format: `username:password`. – AlikElzin-kilaka Mar 09 '18 at 07:06
  • 1
    I found this solution close but not quite correct. As the documentation (confusingly) states and the [source link shows](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/java/io/swagger/codegen/auth/AuthParser.java#L29), in addition to parsing a string for an auth header `key:value` pair via a literal `:` delimiter, it is also expecting the _key and value_ to be UTF-8 URLEncoded. e.g. to pass an `Authorization` header with base64 creds of `admin:admin` (`Basic YWRtaW46YWRtaW4=`) the final arg should be `-a Authorization:Basic%20YWRtaW46YWRtaW4%3D` – christian.d Jun 15 '20 at 06:05
  • 4
    Surely there must be some way to provide credentials without hard-coding them into the source code generation process. Aside from being insecure, does that mean we need to regenerate and recompile our code if a password changes? – Jesse Barnum Jan 30 '21 at 18:11
0

To provide credentials to all requests:

var creds = new NetworkCredential("username", "password");
var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(creds.UserName + ":" + creds.Password));
            
Configuration.Default.AddDefaultHeader("Authorization", "Basic " + encoded);

//use the API
var searchAPI = new SearchAPI();
var files = searchAPI.GetFiles();

To provide the credentials to just one API call:

var creds = new NetworkCredential("username", "password");
var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(creds.UserName + ":" + creds.Password));

var searchAPI = new SearchAPI();
searchAPI.Configuration.AddDefaultHeader("Authorization", "Basic " + encoded);

//use the API
var files = searchAPI.GetFiles();
Fidel
  • 7,027
  • 11
  • 57
  • 81
0

An alternative is to use a custom authenticator.

var basicAuthenticator = new BasicAuthenticator(Configuration.Default.ApiClient.RestClient.BaseUrl.ToString(), "username", "password");
Configuration.Default.ApiClient.RestClient.Authenticator = basicAuthenticator;

Which uses the BasicAuthenticator class:

public class BasicAuthenticator : IAuthenticator
{
    private readonly string _baseUrl;
    private readonly string _userName;
    private readonly string _password;
    private readonly CredentialCache _credentialCache;

    public BasicAuthenticator(string baseUrl, string userName, string password)
    {
        _baseUrl = baseUrl;
        _userName = userName;
        _password = password;

        _credentialCache = new CredentialCache
        {
            {new Uri(_baseUrl), "Basic", new NetworkCredential(_userName, _password)}
        };
    }

    public void Authenticate(IRestClient client, IRestRequest request)
    {
        request.Credentials = _credentialCache;

        if (request.Parameters.Any(parameter =>
                        parameter.Name.Equals("Authorization", StringComparison.OrdinalIgnoreCase)))
        {
            return;
        }
        request.AddParameter("Authorization", GetBasicAuthHeaderValue(), ParameterType.HttpHeader);
    }


    private string GetBasicAuthHeaderValue()
    {
        return string.Format("Basic {0}",
                        Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}",
                            _userName, _password))));
    }
}

There's a known issue with RestSharp that it won't provide the Basic Auth details to second request (after a redirect). Using the above authenticator resolves that.

Fidel
  • 7,027
  • 11
  • 57
  • 81