swagger-api / swagger-api/swagger-codegen

Swagger 2 Feign client code oAuth flow throwing error url values must be not be absolute

Open
#11,947 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

I exposed Rest APIs, and I generated client code using Swagger 2 Java language with Feign library. The code gen generated the below OAuth RequestInterceptor. I am getting the below error when I use the oAuth as auth

Swagger-codegen version

swagger-codegen-maven-plugin v2.4.28

Dependencies used

swagger-codegen-maven-plugin v2.4.28
feign-version 11.6
feign-form-version 3.8.0
oltu-version 1.0.1
Java 8

Swagger declaration file

{
    "swagger": "2.0",
    "info": {
        "description": "app API Custom documentation",
        "version": "1.0.1",
        "title": "app API Custom"
    },
    "host": "localhost:8080",
    "basePath": "/app",
    "tags": [
        {
            "name": "user-resource",
            "description": "User Resource"
        }
    ],
    "paths": {
        "/api/users": {
            "get": {
                "tags": [
                    "user"
                ],
                "summary": "get all user information",
                "operationId": "getAllUsers",
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "description": "Page number of the requested page",
                        "required": false,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "size",
                        "in": "query",
                        "description": "Size of a page",
                        "required": false,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
                        "required": false,
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "collectionFormat": "multi"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/UserDTO"
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                },
                "security": [
                    {
                        "password-oauth2": [
                            "openid"
                        ]
                    }
                ],
                "deprecated": false
            },
            "post": {
                "tags": [
                    "user"
                ],
                "summary": "create user information",
                "operationId": "createUser",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "in": "body",
                        "name": "userDTO",
                        "description": "userDTO",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/UserDTO"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/UserDTO"
                        }
                    },
                    "201": {
                        "description": "Created"
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                },
                "security": [
                    {
                        "client-credentils-oauth2": [
                            "user.create"
                        ]
                    }
                ],
                "deprecated": false
            },
            "put": {
                "tags": [
                    "user"
                ],
                "summary": "update user information",
                "operationId": "updateUser",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "in": "body",
                        "name": "userDTO",
                        "description": "userDTO",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/UserDTO"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/UserDTO"
                        }
                    },
                    "201": {
                        "description": "Created"
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                },
                "security": [
                    {
                        "password-oauth2": [
                            "openid"
                        ],
                        "client-credentils-oauth2": [
                            "user.create"
                        ]
                    }
                ],
                "deprecated": false
            }
        }
    },
    "securityDefinitions": {
        "client-credentils-oauth2": {
            "type": "oauth2",
            "tokenUrl": "http://localhost:8080/app/oauth/token",
            "flow": "application",
            "scopes": {
                "user.create": "for admin operations"
            }
        },
        "password-oauth2": {
            "type": "oauth2",
            "tokenUrl": "http://localhost:8080/app/oauth/token",
            "flow": "password",
            "scopes": {
                "openid": "for user operations"
            }
        }
    },
    "definitions": {
        "UserDTO": {
            "type": "object",
            "properties": {
                "activated": {
                    "type": "boolean"
                },
                "authorities": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "createdBy": {
                    "type": "string"
                },
                "createdDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "email": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 100
                },
                "firstName": {
                    "type": "string",
                    "minLength": 0,
                    "maxLength": 50
                },
                "id": {
                    "type": "integer",
                    "format": "int64"
                },
                "imageUrl": {
                    "type": "string",
                    "minLength": 0,
                    "maxLength": 256
                },
                "langKey": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 6
                },
                "lastModifiedBy": {
                    "type": "string"
                },
                "lastModifiedDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "lastName": {
                    "type": "string",
                    "minLength": 0,
                    "maxLength": 50
                },
                "login": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 50,
                    "pattern": "^[_'.@A-Za-z0-9-]*$"
                },
                "password": {
                    "type": "string"
                }
            },
            "title": "UserDTO"
        }
    }
}

Steps to reproduce

  1. Generate swagger client code using swagger-codegen-maven-plugin v2.4.28
<plugin>
			    <groupId>io.swagger</groupId>
			    <artifactId>swagger-codegen-maven-plugin</artifactId>
			    <version>2.4.28</version>
				<executions>
					<execution>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<!-- specify the swagger yaml -->
							<inputSpec>http://localhost:8080/app/v2/api-docs</inputSpec>
							
							<language>java</language>

							<!-- hint: if you want to generate java server code, e.g. based on 
								Spring Boot, you can use the following target: <language>spring</language> -->

							<!-- pass any necessary config options -->
							<configOptions>
                                <dateLibrary>legacy</dateLibrary>
                            </configOptions>

							<!-- override the default library to jersey2 -->
							<library>feign</library>

							<apiPackage>com.sam.feign.clients</apiPackage>

							<modelPackage>com.sam.feign.dto</modelPackage>
							
						</configuration>
					</execution>
				</executions>
			</plugin>
  1. Run the unit test using below code
UserApi api = new ApiClient("client-credentils-oauth2","admin", "admin", null, null).buildClient(UserApi.class);
api.getUser(login, tenant)

Error trace

feign.RetryableException: url values must be not be absolute.
	at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:95)
	at com.sam.feign.auth.OAuth.apply(OAuth.java:83)
	at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:161)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
	at com.sun.proxy.$Proxy9.getUser(Unknown Source)
	at com.sam.feign.clients.UserApiTest.getUserTest(UserApiTest.java:38)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.IllegalArgumentException: url values must be not be absolute.
	at feign.RequestTemplate.uri(RequestTemplate.java:434)
	at feign.RequestTemplate.uri(RequestTemplate.java:421)
	at feign.RequestTemplate.append(RequestTemplate.java:388)
	at com.sam.feign.auth.OAuth$OAuthFeignClient.execute(OAuth.java:163)
	at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
	at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:55)
	at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:71)
	at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:93)
	... 34 more

Suggest a fix/enhancement

I made the few changes in the oAuth template file to make it work.

      public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
                String requestMethod, Class<T> responseClass)
                        throws OAuthSystemException, OAuthProblemException {
            // Added the below 3 lines
            URI targetUri = URI.create(uri);
            String target = targetUri.getScheme() + "://" + targetUri.getAuthority() ;
            String path  = targetUri.getPath(); 
            
            RequestTemplate req = new RequestTemplate()
                    .uri(path) 
                    .method(requestMethod)
                    .body(request.getBody())
                    .target(target);  // Added this line

            for (Entry<String, String> entry : headers.entrySet()) {
                req.header(entry.getKey(), entry.getValue());
            }
            req = req.resolve(new HashMap<String, Object>()); // Added this line
            Response feignResponse;
            String body = "";
            try {
                feignResponse = client.execute(req.request(), new Options());
                body = Util.toString(feignResponse.body().asReader());
            } catch (IOException e) {
                throw new OAuthSystemException(e);
            }

            String contentType = null;
            Collection<String> contentTypeHeader =  feignResponse.headers().get("Content-Type");
            if(contentTypeHeader != null) {
                contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
            }

            return OAuthClientResponseFactory.createCustomResponse(
                    body,
                    contentType,
                    feignResponse.status(),
                    responseClass
            );
        }

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the generated com.sam.feign.auth.OAuth.updateAccessToken method at OAuth.java:95 and the Feign 11.6 URL error. Reproduce the client generation using the swagger-codegen Maven plugin v2.4.28, the provided Swagger definition, and the Feign library configuration. Done means the generated client obtains an OAuth token and calls UserApi without the absolute-URL exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.