keycloak-uncached

[KEYCLOAK-7147] - Support obtaining a buffered input stream

4/12/2018 10:43:59 AM

Details

diff --git a/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java b/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java
index 1a0eb9c..0d984eb 100755
--- a/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java
+++ b/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java
@@ -27,6 +27,9 @@ import javax.security.cert.X509Certificate;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.SecurityContext;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
@@ -51,6 +54,8 @@ public class JaxrsHttpFacade implements OIDCHttpFacade {
 
     protected class RequestFacade implements OIDCHttpFacade.Request {
 
+        private InputStream inputStream;
+
         @Override
         public String getFirstParam(String param) {
             throw new RuntimeException("NOT IMPLEMENTED");
@@ -108,6 +113,19 @@ public class JaxrsHttpFacade implements OIDCHttpFacade {
 
         @Override
         public InputStream getInputStream() {
+            return getInputStream(false);
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
+            if (inputStream != null) {
+                return inputStream;
+            }
+
+            if (buffered) {
+                return inputStream = new BufferedInputStream(requestContext.getEntityStream());
+            }
+
             return requestContext.getEntityStream();
         }
 
diff --git a/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 67c9f08..47c9a93 100755
--- a/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -36,6 +36,8 @@ import javax.security.cert.X509Certificate;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
@@ -265,6 +267,8 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
         public Request getRequest() {
             return new Request() {
 
+                private InputStream inputStream;
+
                 @Override
                 public String getFirstParam(String param) {
                     return servletRequest.getParameter(param);
@@ -314,10 +318,27 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
 
                 @Override
                 public InputStream getInputStream() {
+                    return getInputStream(false);
+                }
+
+                @Override
+                public InputStream getInputStream(boolean buffered) {
+                    if (inputStream != null) {
+                        return inputStream;
+                    }
+
+                    if (buffered) {
+                        try {
+                            return inputStream = new BufferedInputStream(servletRequest.getInputStream());
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+
                     try {
                         return servletRequest.getInputStream();
-                    } catch (IOException ioe) {
-                        throw new RuntimeException(ioe);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
                     }
                 }
 
diff --git a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletRequest.java b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletRequest.java
index 848ca45..f4fa074 100755
--- a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletRequest.java
+++ b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletRequest.java
@@ -24,6 +24,8 @@ import org.keycloak.adapters.spi.LogoutError;
 import org.springframework.util.Assert;
 
 import javax.servlet.http.HttpServletRequest;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -40,6 +42,7 @@ import java.util.List;
 class WrappedHttpServletRequest implements Request {
 
     private final HttpServletRequest request;
+    private InputStream inputStream;
 
     /**
      * Creates a new request for the given <code>HttpServletRequest</code>
@@ -122,10 +125,27 @@ class WrappedHttpServletRequest implements Request {
 
     @Override
     public InputStream getInputStream() {
+        return getInputStream(false);
+    }
+
+    @Override
+    public InputStream getInputStream(boolean buffered) {
+        if (inputStream != null) {
+            return inputStream;
+        }
+
+        if (buffered) {
+            try {
+                return inputStream = new BufferedInputStream(request.getInputStream());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
         try {
             return request.getInputStream();
         } catch (IOException e) {
-            throw new RuntimeException("Unable to get request input stream", e);
+            throw new RuntimeException(e);
         }
     }
 
diff --git a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
index 1d27810..bda24bb 100644
--- a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
+++ b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
@@ -40,6 +40,8 @@ import org.wildfly.security.http.Scope;
 
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.cert.X509Certificate;
+
+import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -158,6 +160,8 @@ class ElytronHttpFacade implements OIDCHttpFacade {
     @Override
     public Request getRequest() {
         return new Request() {
+            private InputStream inputStream;
+
             @Override
             public String getMethod() {
                 return request.getRequestMethod();
@@ -230,6 +234,19 @@ class ElytronHttpFacade implements OIDCHttpFacade {
 
             @Override
             public InputStream getInputStream() {
+                return getInputStream(false);
+            }
+
+            @Override
+            public InputStream getInputStream(boolean buffered) {
+                if (inputStream != null) {
+                    return inputStream;
+                }
+
+                if (buffered) {
+                    return inputStream = new BufferedInputStream(request.getInputStream());
+                }
+
                 return request.getInputStream();
             }
 
diff --git a/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/ElytronHttpFacade.java b/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/ElytronHttpFacade.java
index 1458dd9..8b31a31 100644
--- a/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/ElytronHttpFacade.java
+++ b/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/ElytronHttpFacade.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.adapters.saml.elytron;
 
+import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -146,6 +147,8 @@ class ElytronHttpFacade implements HttpFacade {
     @Override
     public Request getRequest() {
         return new Request() {
+            private InputStream inputStream;
+
             @Override
             public String getMethod() {
                 return request.getRequestMethod();
@@ -207,6 +210,19 @@ class ElytronHttpFacade implements HttpFacade {
 
             @Override
             public InputStream getInputStream() {
+                return getInputStream(false);
+            }
+
+            @Override
+            public InputStream getInputStream(boolean buffered) {
+                if (inputStream != null) {
+                    return inputStream;
+                }
+
+                if (buffered) {
+                    return inputStream = new BufferedInputStream(request.getInputStream());
+                }
+
                 return request.getInputStream();
             }
 
diff --git a/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/HttpFacade.java b/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/HttpFacade.java
index 2429286..0636ebc 100755
--- a/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/HttpFacade.java
+++ b/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/HttpFacade.java
@@ -69,6 +69,7 @@ public interface HttpFacade {
         String getHeader(String name);
         List<String> getHeaders(String name);
         InputStream getInputStream();
+        InputStream getInputStream(boolean buffered);
 
         String getRemoteAddr();
         void setError(AuthenticationError error);
diff --git a/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java b/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java
index dac7973..d097ee4 100755
--- a/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java
+++ b/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java
@@ -25,6 +25,8 @@ import org.keycloak.common.util.UriUtils;
 
 import javax.security.cert.X509Certificate;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -69,6 +71,9 @@ public class JettyHttpFacade implements HttpFacade {
     }
 
     protected class RequestFacade implements Request {
+
+        private InputStream inputStream;
+
         @Override
         public String getURI() {
             StringBuffer buf = request.getRequestURL();
@@ -128,6 +133,23 @@ public class JettyHttpFacade implements HttpFacade {
 
         @Override
         public InputStream getInputStream() {
+            return getInputStream(false);
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
+            if (inputStream != null) {
+                return inputStream;
+            }
+
+            if (buffered) {
+                try {
+                    return inputStream = new BufferedInputStream(request.getInputStream());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
             try {
                 return request.getInputStream();
             } catch (IOException e) {
diff --git a/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/ServletHttpFacade.java b/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/ServletHttpFacade.java
index 11e4f93..f77b1e3 100755
--- a/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/ServletHttpFacade.java
+++ b/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/ServletHttpFacade.java
@@ -27,6 +27,8 @@ import org.keycloak.common.util.UriUtils;
 import javax.security.cert.X509Certificate;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -51,6 +53,9 @@ public class ServletHttpFacade implements HttpFacade {
     }
 
     protected class RequestFacade implements Request {
+
+        private InputStream inputStream;
+
         @Override
         public String getMethod() {
             return request.getMethod();
@@ -132,6 +137,23 @@ public class ServletHttpFacade implements HttpFacade {
 
         @Override
         public InputStream getInputStream() {
+            return getInputStream(false);
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
+            if (inputStream != null) {
+                return inputStream;
+            }
+
+            if (buffered) {
+                try {
+                    return inputStream = new BufferedInputStream(request.getInputStream());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
             try {
                 return request.getInputStream();
             } catch (IOException e) {
diff --git a/adapters/spi/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/CatalinaHttpFacade.java b/adapters/spi/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/CatalinaHttpFacade.java
index 631474e..c2813b2 100755
--- a/adapters/spi/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/CatalinaHttpFacade.java
+++ b/adapters/spi/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/CatalinaHttpFacade.java
@@ -26,6 +26,8 @@ import org.keycloak.common.util.UriUtils;
 
 import javax.security.cert.X509Certificate;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -69,6 +71,9 @@ public class CatalinaHttpFacade implements HttpFacade {
     }
 
     protected class RequestFacade implements Request {
+
+        private InputStream inputStream;
+
         @Override
         public String getURI() {
             StringBuffer buf = request.getRequestURL();
@@ -136,6 +141,23 @@ public class CatalinaHttpFacade implements HttpFacade {
 
         @Override
         public InputStream getInputStream() {
+            return getInputStream(false);
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
+            if (inputStream != null) {
+                return inputStream;
+            }
+
+            if (buffered) {
+                try {
+                    return inputStream = new BufferedInputStream(request.getInputStream());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
             try {
                 return request.getInputStream();
             } catch (IOException e) {
diff --git a/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/UndertowHttpFacade.java b/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/UndertowHttpFacade.java
index 21102f1..d47b363 100755
--- a/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/UndertowHttpFacade.java
+++ b/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/UndertowHttpFacade.java
@@ -19,6 +19,10 @@ package org.keycloak.adapters.undertow;
 
 import io.undertow.server.HttpServerExchange;
 import io.undertow.server.handlers.CookieImpl;
+import io.undertow.server.handlers.form.FormData;
+import io.undertow.server.handlers.form.FormData.FormValue;
+import io.undertow.server.handlers.form.FormDataParser;
+import io.undertow.server.handlers.form.FormParserFactory;
 import io.undertow.util.AttachmentKey;
 import io.undertow.util.Headers;
 import io.undertow.util.HttpString;
@@ -28,6 +32,8 @@ import org.keycloak.adapters.spi.LogoutError;
 import org.keycloak.common.util.KeycloakUriBuilder;
 
 import javax.security.cert.X509Certificate;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -75,6 +81,11 @@ public class UndertowHttpFacade implements HttpFacade {
     }
 
     protected class RequestFacade implements Request {
+
+        private InputStream inputStream;
+        private final FormParserFactory formParserFactory = FormParserFactory.builder().build();
+        private FormData formData;
+
         @Override
         public String getURI() {
             KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(exchange.getRequestURI())
@@ -96,7 +107,34 @@ public class UndertowHttpFacade implements HttpFacade {
 
         @Override
         public String getFirstParam(String param) {
-            throw new RuntimeException("Not implemented yet");
+            Deque<String> values = exchange.getQueryParameters().get(param);
+
+            if (values != null && !values.isEmpty()) {
+                return values.getFirst();
+            }
+
+            if (formData == null && "post".equalsIgnoreCase(getMethod())) {
+                FormDataParser parser = formParserFactory.createParser(exchange);
+                try {
+                    formData = parser.parseBlocking();
+                } catch (IOException cause) {
+                    throw new RuntimeException("Failed to parse form parameters", cause);
+                }
+            }
+
+            if (formData != null) {
+                Deque<FormValue> formValues = formData.get(param);
+
+                if (formValues != null && !formValues.isEmpty()) {
+                    FormValue firstValue = formValues.getFirst();
+
+                    if (!firstValue.isFile()) {
+                        return firstValue.getValue();
+                    }
+                }
+            }
+
+            return null;
         }
 
         @Override
@@ -136,7 +174,21 @@ public class UndertowHttpFacade implements HttpFacade {
 
         @Override
         public InputStream getInputStream() {
+            return getInputStream(false);
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
             if (!exchange.isBlocking()) exchange.startBlocking();
+
+            if (inputStream != null) {
+                return inputStream;
+            }
+
+            if (buffered) {
+                return inputStream = new BufferedInputStream(exchange.getInputStream());
+            }
+
             return exchange.getInputStream();
         }
 
diff --git a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
index cd912d7..ef84de1 100755
--- a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
+++ b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
@@ -43,6 +43,8 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -171,6 +173,8 @@ public class OfflineAccessPortalServlet extends HttpServlet {
             public Request getRequest() {
                 return new Request() {
 
+                    private InputStream inputStream;
+
                     @Override
                     public String getMethod() {
                         return servletRequest.getMethod();
@@ -220,10 +224,27 @@ public class OfflineAccessPortalServlet extends HttpServlet {
 
                     @Override
                     public InputStream getInputStream() {
+                        return getInputStream(false);
+                    }
+
+                    @Override
+                    public InputStream getInputStream(boolean buffered) {
+                        if (inputStream != null) {
+                            return inputStream;
+                        }
+
+                        if (buffered) {
+                            try {
+                                return inputStream = new BufferedInputStream(servletRequest.getInputStream());
+                            } catch (IOException e) {
+                                throw new RuntimeException(e);
+                            }
+                        }
+
                         try {
                             return servletRequest.getInputStream();
-                        } catch (IOException ioe) {
-                            throw new RuntimeException(ioe);
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
                         }
                     }