From e4dc48dcdd7d31e1ce93aaaaa5179de3ba6fc395 Mon Sep 17 00:00:00 2001
From: aanno2 <aanno.trash@gmail.com>
Date: Wed, 13 Nov 2019 16:27:31 +0100
Subject: [PATCH 1/2] 
 https://github.com/OpenAPITools/openapi-generator/pull/4452 squashed from
 original, and better author

---
 .../openapitools/codegen/CodegenSecurity.java |  38 ++++-
 .../openapitools/codegen/DefaultCodegen.java  |  30 +++-
 .../codegen/DefaultGenerator.java             |  27 ++++
 .../openapitools/codegen/OpenIdConnect.java   | 141 ++++++++++++++++++
 .../languages/HaskellHttpClientCodegen.java   |   1 +
 .../codegen/languages/JavaClientCodegen.java  |   6 +-
 .../codegen/languages/RustServerCodegen.java  |   2 +-
 .../codegen/utils/ProcessUtils.java           |  24 +++
 .../codegen/OpenIdConnectTest.java            |  58 +++++++
 .../keycloak-openid-configuration.json        | 121 +++++++++++++++
 10 files changed, 439 insertions(+), 9 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenIdConnect.java
 create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenIdConnectTest.java
 create mode 100644 modules/openapi-generator/src/test/resources/3_0/openidconnect/keycloak-openid-configuration.json

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenSecurity.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenSecurity.java
index 419aee1d4ad..cb6012caaec 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenSecurity.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenSecurity.java
@@ -28,7 +28,8 @@ public class CodegenSecurity {
     public String name;
     public String type;
     public String scheme;
-    public Boolean hasMore, isBasic, isOAuth, isApiKey;
+    // if isOpenIdConnect is true => isOAuth is also true, as Oidc is a (more) standardized way of OAuth2
+    public Boolean hasMore, isBasic, isOAuth, isOpenIdConnect, isApiKey;
     // is Basic is true for all http authentication type.
     // Those are to differentiate basic and bearer authentication
     // isHttpSignature is to support HTTP signature authorization scheme.
@@ -44,6 +45,36 @@ public class CodegenSecurity {
     public List<Map<String, Object>> scopes;
     public Boolean isCode, isPassword, isApplication, isImplicit;
 
+    public static CodegenSecurity copy(CodegenSecurity toCopy) {
+        CodegenSecurity result = new CodegenSecurity();
+        if (toCopy.vendorExtensions != null) {
+            result.vendorExtensions = new HashMap<>(toCopy.vendorExtensions);
+        }
+        result.scopes = new ArrayList<>();
+        if (toCopy.scopes != null) {
+            for (Map<String, Object> m : toCopy.scopes) {
+                result.scopes.add(new HashMap<>(m));
+            }
+        }
+
+        result.authorizationUrl = toCopy.authorizationUrl;
+        result.flow = toCopy.flow;
+        result.tokenUrl = toCopy.tokenUrl;
+
+        result.name = toCopy.name;
+        result.isImplicit = toCopy.isImplicit;
+        result.isCode = toCopy.isCode;
+        result.isOpenIdConnect = toCopy.isOpenIdConnect;
+        result.isOAuth = toCopy.isOAuth;
+        result.isBasic = toCopy.isBasic;
+        result.isApiKey = toCopy.isApiKey;
+
+        return result;
+    }
+
+    public CodegenSecurity() {
+    }
+
     // Return a copy of the security object, filtering out any scopes from the passed-in list.
     public CodegenSecurity filterByScopeNames(List<String> filterScopes) {
         CodegenSecurity filteredSecurity = new CodegenSecurity();
@@ -56,6 +87,7 @@ public class CodegenSecurity {
         filteredSecurity.isHttpSignature = isHttpSignature;
         filteredSecurity.isBasicBearer = isBasicBearer;
         filteredSecurity.isApiKey = isApiKey;
+        filteredSecurity.isOpenIdConnect = isOpenIdConnect;
         filteredSecurity.isOAuth = isOAuth;
         filteredSecurity.keyParamName = keyParamName;
         filteredSecurity.isCode = isCode;
@@ -99,6 +131,7 @@ public class CodegenSecurity {
                 Objects.equals(hasMore, that.hasMore) &&
                 Objects.equals(isBasic, that.isBasic) &&
                 Objects.equals(isOAuth, that.isOAuth) &&
+                Objects.equals(isOpenIdConnect, that.isOpenIdConnect) &&
                 Objects.equals(isApiKey, that.isApiKey) &&
                 Objects.equals(isBasicBasic, that.isBasicBasic) &&
                 Objects.equals(isHttpSignature, that.isHttpSignature) &&
@@ -122,7 +155,7 @@ public class CodegenSecurity {
     @Override
     public int hashCode() {
 
-        return Objects.hash(name, type, scheme, hasMore, isBasic, isOAuth, isApiKey,
+        return Objects.hash(name, type, scheme, hasMore, isBasic, isOAuth, isOpenIdConnect, isApiKey,
                 isBasicBasic, isHttpSignature, isBasicBearer, bearerFormat, vendorExtensions,
                 keyParamName, isKeyInQuery, isKeyInHeader, isKeyInCookie, flow,
                 authorizationUrl, tokenUrl, scopes, isCode, isPassword, isApplication, isImplicit);
@@ -137,6 +170,7 @@ public class CodegenSecurity {
         sb.append(", hasMore=").append(hasMore);
         sb.append(", isBasic=").append(isBasic);
         sb.append(", isOAuth=").append(isOAuth);
+        sb.append(", isOpenIdConnect=").append(isOpenIdConnect);
         sb.append(", isApiKey=").append(isApiKey);
         sb.append(", isBasicBasic=").append(isBasicBasic);
         sb.append(", isHttpSignature=").append(isHttpSignature);
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index d4cc2541437..7fc7a25afa1 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -63,6 +63,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.TimeUnit;
@@ -4251,12 +4252,14 @@ public class DefaultCodegen implements CodegenConfig {
             }
 
             if (SecurityScheme.Type.APIKEY.equals(securityScheme.getType())) {
-                cs.isBasic = cs.isOAuth = false;
+                cs.isBasic = cs.isOAuth = cs.isOpenIdConnect = false;
                 cs.isApiKey = true;
                 cs.keyParamName = securityScheme.getName();
                 cs.isKeyInHeader = securityScheme.getIn() == SecurityScheme.In.HEADER;
                 cs.isKeyInQuery = securityScheme.getIn() == SecurityScheme.In.QUERY;
                 cs.isKeyInCookie = securityScheme.getIn() == SecurityScheme.In.COOKIE;  //it assumes a validation step prior to generation. (cookie-auth supported from OpenAPI 3.0.0)
+
+                codegenSecurities.add(cs);
             } else if (SecurityScheme.Type.HTTP.equals(securityScheme.getType())) {
                 cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isOAuth = false;
                 cs.isBasic = true;
@@ -4274,13 +4277,17 @@ public class DefaultCodegen implements CodegenConfig {
                     cs.isHttpSignature = true;
                     once(LOGGER).warn("Security scheme 'HTTP signature' is a draft IETF RFC and subject to change.");
                 }
+
+                codegenSecurities.add(cs);
             } else if (SecurityScheme.Type.OAUTH2.equals(securityScheme.getType())) {
                 cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isBasic = false;
+                cs.isOpenIdConnect = false;
                 cs.isOAuth = true;
                 final OAuthFlows flows = securityScheme.getFlows();
                 if (securityScheme.getFlows() == null) {
                     throw new RuntimeException("missing oauth flow in " + cs.name);
                 }
+                // TODO: Like in the openIdConnect case this could be more that one flow
                 if (flows.getPassword() != null) {
                     setOauth2Info(cs, flows.getPassword());
                     cs.isPassword = true;
@@ -4300,9 +4307,24 @@ public class DefaultCodegen implements CodegenConfig {
                 } else {
                     throw new RuntimeException("Could not identify any oauth2 flow in " + cs.name);
                 }
-            }
 
-            codegenSecurities.add(cs);
+                codegenSecurities.add(cs);
+            } else if (SecurityScheme.Type.OPENIDCONNECT.equals(securityScheme.getType())) {
+                cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isBasic = false;
+                cs.isOAuth = cs.isOpenIdConnect = true;
+                // https://swagger.io/docs/specification/authentication/openid-connect-discovery/
+                // we need to implement https://openid.net/specs/openid-connect-discovery-1_0.html
+                // and fill out our standard oauth2 stuff https://swagger.io/docs/specification/authentication/oauth2/
+                // from .well-known/openid-configuration
+                try {
+                    OpenIdConnect openIdConnect = new OpenIdConnect(this,
+                            securityScheme.getOpenIdConnectUrl()).retrieve();
+                    List<CodegenSecurity> securities = openIdConnect.getCodegenSecurities(cs);
+                    codegenSecurities.addAll(securities);
+                } catch (IOException e) {
+                    throw new RuntimeException("openIdConnect error: " + e, e);
+                }
+            }
         }
 
         // sort auth methods to maintain the same order
@@ -5323,7 +5345,7 @@ public class DefaultCodegen implements CodegenConfig {
         return new ArrayList<>(requestBody.getContent().keySet()).get(0);
     }
 
-    private void setOauth2Info(CodegenSecurity codegenSecurity, OAuthFlow flow) {
+    void setOauth2Info(CodegenSecurity codegenSecurity, OAuthFlow flow) {
         codegenSecurity.authorizationUrl = flow.getAuthorizationUrl();
         codegenSecurity.tokenUrl = flow.getTokenUrl();
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
index 1681434c442..70d25dffca3 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
@@ -920,6 +920,10 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
                 bundle.put("hasOAuthMethods", true);
                 bundle.put("oauthMethods", getOAuthMethods(authMethods));
             }
+            if (hasOpenIdConnectMethods(authMethods)) {
+                bundle.put("hasOpenIdConnectMethods", true);
+                bundle.put("openIdConnectMethods", getOpenIdConnectMethods(authMethods));
+            }
 
             if (hasBearerMethods(authMethods)) {
                 bundle.put("hasBearerMethods", true);
@@ -1445,6 +1449,16 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
         return false;
     }
 
+    private boolean hasOpenIdConnectMethods(List<CodegenSecurity> authMethods) {
+        for (CodegenSecurity cs : authMethods) {
+            if (Boolean.TRUE.equals(cs.isOpenIdConnect)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     private boolean hasBearerMethods(List<CodegenSecurity> authMethods) {
         for (CodegenSecurity cs : authMethods) {
             if (Boolean.TRUE.equals(cs.isBasicBearer)) {
@@ -1513,4 +1527,17 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
             return super.writeToFile(filename, contents);
         }
     }
+
+    private List<CodegenSecurity> getOpenIdConnectMethods(List<CodegenSecurity> authMethods) {
+        List<CodegenSecurity> oauthMethods = new ArrayList<>();
+
+        for (CodegenSecurity cs : authMethods) {
+            if (Boolean.TRUE.equals(cs.isOpenIdConnect)) {
+                oauthMethods.add(cs);
+            }
+        }
+
+        return oauthMethods;
+    }
+
 }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenIdConnect.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenIdConnect.java
new file mode 100644
index 00000000000..f9138c230fd
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenIdConnect.java
@@ -0,0 +1,141 @@
+package org.openapitools.codegen;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.v3.oas.models.security.OAuthFlow;
+import io.swagger.v3.oas.models.security.Scopes;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+
+public class OpenIdConnect {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    private final DefaultCodegen codegen;
+
+    private final URL discovery;
+
+    private JsonNode rootNode;
+
+    // https://stackoverflow.com/questions/28658735/what-are-keycloaks-oauth2-openid-connect-endpoints
+    private Set<String> grantTypes = new HashSet<>();
+    private Set<String> responseTypes = new HashSet<>();
+    private Set<String> claims = new HashSet<>();
+    private Set<String> scopes = new HashSet<>();
+
+    private String authorizationUrl;
+    private String tokenUrl;
+
+    public OpenIdConnect(DefaultCodegen codegen, String url) throws MalformedURLException {
+        this.codegen = codegen;
+        this.discovery = new URL(url);
+    }
+
+    public OpenIdConnect retrieve() throws IOException {
+        if (rootNode == null) {
+            rootNode = mapper.readTree(discovery);
+            authorizationUrl = rootNode.get("authorization_endpoint").asText();
+            tokenUrl = rootNode.get("token_endpoint").asText();
+            JsonNode grantArray = rootNode.get("grant_types_supported");
+            if (grantArray.isArray()) {
+                for (JsonNode el: grantArray) {
+                    grantTypes.add(el.asText());
+                }
+            }
+            JsonNode responseArray = rootNode.get("response_types_supported");
+            if (responseArray.isArray()) {
+                for (JsonNode el: responseArray) {
+                    responseTypes.add(el.asText());
+                }
+            }
+            JsonNode claimArray = rootNode.get("claims_supported");
+            if (claimArray.isArray()) {
+                for (JsonNode el: claimArray) {
+                    claims.add(el.asText());
+                }
+            }
+            JsonNode scopeArray = rootNode.get("scopes_supported");
+            if (scopeArray.isArray()) {
+                for (JsonNode el: scopeArray) {
+                    scopes.add(el.asText());
+                }
+            }
+        }
+        return this;
+    }
+
+    public List<CodegenSecurity> getCodegenSecurities(CodegenSecurity toCopy) {
+        CodegenSecurity cs = CodegenSecurity.copy(toCopy);
+        // cs.name = "openIdConnect";
+        cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isBasic = false;
+        cs.isOpenIdConnect = true;
+        cs.isOAuth = true;
+        cs.authorizationUrl = authorizationUrl;
+        cs.tokenUrl = tokenUrl;
+        cs.scopes = new ArrayList<>();
+
+        Scopes flowScopes = new Scopes();
+        for (String s: scopes) {
+            // we have no description
+            flowScopes.addString(s, s);
+        }
+        OAuthFlow flow = new OAuthFlow();
+        flow = flow.authorizationUrl(authorizationUrl).tokenUrl(tokenUrl).scopes(flowScopes);
+        cs.scopes.add(new HashMap<>(flowScopes));
+
+        if (grantTypes.isEmpty()) {
+            throw new RuntimeException("missing oauth flow in " + cs.name);
+        }
+
+        List<CodegenSecurity> result = new ArrayList<>();
+        // Can be all of this at the same time!
+        if (grantTypes.contains("password")) {
+            CodegenSecurity csPassword = CodegenSecurity.copy(cs);
+            codegen.setOauth2Info(csPassword, flow);
+            csPassword.isPassword = true;
+            csPassword.isImplicit = false;
+            csPassword.isApplication = false;
+            csPassword.isCode = false;
+            csPassword.flow = "password";
+            result.add(csPassword);
+        }
+        if (grantTypes.contains("implicit")) {
+            CodegenSecurity csImplicit = CodegenSecurity.copy(cs);
+            codegen.setOauth2Info(csImplicit, flow);
+            csImplicit.isPassword = false;
+            csImplicit.isImplicit = true;
+            csImplicit.isApplication = false;
+            csImplicit.isCode = false;
+            csImplicit.flow = "implicit";
+            result.add(csImplicit);
+        }
+        if (grantTypes.contains("client_credentials")) {
+            CodegenSecurity csClient = CodegenSecurity.copy(cs);
+            codegen.setOauth2Info(csClient, flow);
+            csClient.isPassword = false;
+            csClient.isImplicit = false;
+            csClient.isApplication = true;
+            csClient.isCode = false;
+            csClient.flow = "application";
+            result.add(csClient);
+        }
+        if (grantTypes.contains("authorization_code")) {
+            CodegenSecurity csCode = CodegenSecurity.copy(cs);
+            codegen.setOauth2Info(csCode, flow);
+            csCode.isPassword = false;
+            csCode.isImplicit = false;
+            csCode.isApplication = false;
+            csCode.isCode = true;
+            csCode.flow = "accessCode";
+            result.add(csCode);
+        }
+        if (result.isEmpty()) {
+            throw new RuntimeException("Could not identify any openIdConnect flow in " + cs.name);
+        }
+        return result;
+    }
+
+}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellHttpClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellHttpClientCodegen.java
index 15a37e681e8..1a472bb26b2 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellHttpClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellHttpClientCodegen.java
@@ -789,6 +789,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
             if (sec.isBasic) prefix = "AuthBasic";
             if (sec.isApiKey) prefix = "AuthApiKey";
             if (sec.isOAuth) prefix = "AuthOAuth";
+            if (sec.isOpenIdConnect) prefix = "AuthOpenIdConnect";
             sec.name = prefix + toTypeName("", sec.name);
         }
         return secs;
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
index e708b1f7e62..33d29507d3b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
@@ -586,13 +586,15 @@ public class JavaClientCodegen extends AbstractJavaCodegen
         }
 
         // for okhttp-gson (default), check to see if OAuth is defined and included OAuth-related files accordingly
-        if ((OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) && ProcessUtils.hasOAuthMethods(objs)) {
+        if ((OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary()))
+                && (ProcessUtils.hasOAuthMethods(objs) || ProcessUtils.hasOpenIdConnectMethods(objs))) {
             supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
             supportingFiles.add(new SupportingFile("auth/RetryingOAuth.mustache", authFolder, "RetryingOAuth.java"));
         }
 
         // google-api-client doesn't use the OpenAPI auth, because it uses Google Credential directly (HttpRequestInitializer)
-        if ((!(GOOGLE_API_CLIENT.equals(getLibrary()) || REST_ASSURED.equals(getLibrary()) || usePlayWS || NATIVE.equals(getLibrary()) || MICROPROFILE.equals(getLibrary()))) && ProcessUtils.hasOAuthMethods(objs)) {
+        if ((!(GOOGLE_API_CLIENT.equals(getLibrary()) || REST_ASSURED.equals(getLibrary()) || usePlayWS || NATIVE.equals(getLibrary()) || MICROPROFILE.equals(getLibrary())))
+                && (ProcessUtils.hasOAuthMethods(objs) || ProcessUtils.hasOpenIdConnectMethods(objs))) {
             supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java"));
             supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java"));
         }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
index 3bad2df6ed0..fc8f3db5be4 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java
@@ -933,7 +933,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
                         headerAuthMethods = true;
                     }
 
-                    if (s.isBasicBasic || s.isBasicBearer || s.isOAuth) {
+                    if (s.isBasicBasic || s.isBasicBearer || s.isOAuth || s.isOpenIdConnect) {
                         headerAuthMethods = true;
                     }
                 }
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ProcessUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ProcessUtils.java
index 91b7b674d66..fa702f03282 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ProcessUtils.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ProcessUtils.java
@@ -70,6 +70,30 @@ public class ProcessUtils {
         return false;
     }
 
+    /**
+     * Returns true if at least one operation has openIdConnect security schema defined
+     *
+     * @param objs Map of operations
+     * @return True if at least one operation has OAuth security schema defined
+     */
+    public static boolean hasOpenIdConnectMethods(Map<String, Object> objs) {
+        Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
+        if (operations != null) {
+            List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
+            for (CodegenOperation operation : ops) {
+                if (operation.authMethods != null && !operation.authMethods.isEmpty()) {
+                    for (CodegenSecurity cs : operation.authMethods) {
+                        if (Boolean.TRUE.equals(cs.isOpenIdConnect)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Returns true if at least one operation has Bearer security schema defined
      *
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenIdConnectTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenIdConnectTest.java
new file mode 100644
index 00000000000..f89374219c7
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenIdConnectTest.java
@@ -0,0 +1,58 @@
+package org.openapitools.codegen;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import static org.testng.AssertJUnit.*;
+
+public class OpenIdConnectTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdConnectTest.class);
+
+    private static final String OPENID_CONFIGURATION = "./3_0/openidconnect/keycloak-openid-configuration.json";
+
+    private DefaultCodegen codegen = new DefaultCodegen();
+
+    @Test
+    public void testOpenIdConfiguration() throws IOException {
+        URL config = Thread.currentThread().getContextClassLoader().getResource(OPENID_CONFIGURATION);
+        OpenIdConnect dut = new OpenIdConnect(codegen, config.toExternalForm()).retrieve();
+        CodegenSecurity cs = new CodegenSecurity();
+        List<CodegenSecurity> securities = dut.getCodegenSecurities(cs);
+
+        assertEquals(4, securities.size());
+
+        CodegenSecurity pw = securities.get(0);
+        assertTrue(pw.isPassword);
+        assertFalse(pw.isImplicit);
+        assertFalse(pw.isApplication);
+        assertFalse(pw.isCode);
+        assertEquals(9, pw.scopes.size());
+
+        CodegenSecurity impl = securities.get(1);
+        assertFalse(impl.isPassword);
+        assertTrue(impl.isImplicit);
+        assertFalse(impl.isApplication);
+        assertFalse(impl.isCode);
+        assertEquals(9, pw.scopes.size());
+
+        CodegenSecurity appl = securities.get(2);
+        assertFalse(appl.isPassword);
+        assertFalse(appl.isImplicit);
+        assertTrue(appl.isApplication);
+        assertFalse(appl.isCode);
+        assertEquals(9, pw.scopes.size());
+
+        CodegenSecurity accessCode = securities.get(3);
+        assertFalse(accessCode.isPassword);
+        assertFalse(accessCode.isImplicit);
+        assertFalse(accessCode.isApplication);
+        assertTrue(accessCode.isCode);
+        assertEquals(9, pw.scopes.size());
+    }
+}
diff --git a/modules/openapi-generator/src/test/resources/3_0/openidconnect/keycloak-openid-configuration.json b/modules/openapi-generator/src/test/resources/3_0/openidconnect/keycloak-openid-configuration.json
new file mode 100644
index 00000000000..3ac42fab788
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/openidconnect/keycloak-openid-configuration.json
@@ -0,0 +1,121 @@
+{
+  "issuer": "http://localhost:8080/auth/realms/master",
+  "authorization_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/auth",
+  "token_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/token",
+  "token_introspection_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/token/introspect",
+  "userinfo_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo",
+  "end_session_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/logout",
+  "jwks_uri": "http://localhost:8080/auth/realms/master/protocol/openid-connect/certs",
+  "check_session_iframe": "http://localhost:8080/auth/realms/master/protocol/openid-connect/login-status-iframe.html",
+  "grant_types_supported": [
+    "authorization_code",
+    "implicit",
+    "refresh_token",
+    "password",
+    "client_credentials"
+  ],
+  "response_types_supported": [
+    "code",
+    "none",
+    "id_token",
+    "token",
+    "id_token token",
+    "code id_token",
+    "code token",
+    "code id_token token"
+  ],
+  "subject_types_supported": [
+    "public",
+    "pairwise"
+  ],
+  "id_token_signing_alg_values_supported": [
+    "PS384",
+    "ES384",
+    "RS384",
+    "HS256",
+    "HS512",
+    "ES256",
+    "RS256",
+    "HS384",
+    "ES512",
+    "PS256",
+    "PS512",
+    "RS512"
+  ],
+  "userinfo_signing_alg_values_supported": [
+    "PS384",
+    "ES384",
+    "RS384",
+    "HS256",
+    "HS512",
+    "ES256",
+    "RS256",
+    "HS384",
+    "ES512",
+    "PS256",
+    "PS512",
+    "RS512",
+    "none"
+  ],
+  "request_object_signing_alg_values_supported": [
+    "PS384",
+    "ES384",
+    "RS384",
+    "ES256",
+    "RS256",
+    "ES512",
+    "PS256",
+    "PS512",
+    "RS512",
+    "none"
+  ],
+  "response_modes_supported": [
+    "query",
+    "fragment",
+    "form_post"
+  ],
+  "registration_endpoint": "http://localhost:8080/auth/realms/master/clients-registrations/openid-connect",
+  "token_endpoint_auth_methods_supported": [
+    "private_key_jwt",
+    "client_secret_basic",
+    "client_secret_post",
+    "client_secret_jwt"
+  ],
+  "token_endpoint_auth_signing_alg_values_supported": [
+    "RS256"
+  ],
+  "claims_supported": [
+    "aud",
+    "sub",
+    "iss",
+    "auth_time",
+    "name",
+    "given_name",
+    "family_name",
+    "preferred_username",
+    "email"
+  ],
+  "claim_types_supported": [
+    "normal"
+  ],
+  "claims_parameter_supported": false,
+  "scopes_supported": [
+    "openid",
+    "address",
+    "email",
+    "microprofile-jwt",
+    "offline_access",
+    "phone",
+    "profile",
+    "roles",
+    "web-origins"
+  ],
+  "request_parameter_supported": true,
+  "request_uri_parameter_supported": true,
+  "code_challenge_methods_supported": [
+    "plain",
+    "S256"
+  ],
+  "tls_client_certificate_bound_access_tokens": true,
+  "introspection_endpoint": "http://localhost:8080/auth/realms/master/protocol/openid-connect/token/introspect"
+}
-- 
GitLab


From eca20184f24b2109a4a8a7e4c54a68572c6a38a6 Mon Sep 17 00:00:00 2001
From: aanno2 <aanno.trash@gmail.com>
Date: Thu, 23 Jan 2020 08:55:41 +0100
Subject: [PATCH 2/2] fixed issue with HaskellHttpClient

---
 .../src/main/java/org/openapitools/codegen/DefaultCodegen.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index 7fc7a25afa1..eacb642f51f 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -4261,7 +4261,7 @@ public class DefaultCodegen implements CodegenConfig {
 
                 codegenSecurities.add(cs);
             } else if (SecurityScheme.Type.HTTP.equals(securityScheme.getType())) {
-                cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isOAuth = false;
+                cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isOAuth = cs.isOpenIdConnect= false;
                 cs.isBasic = true;
                 if ("basic".equals(securityScheme.getScheme())) {
                     cs.isBasicBasic = true;
-- 
GitLab