keycloak-uncached

refactor out resteasy from adapters

12/17/2013 3:07:02 PM

Changes

examples/as7-eap-demo/customer-app/src/main/java/org/jboss/resteasy/example/oauth/CustomerDatabaseClient.java 36(+0 -36)

examples/as7-eap-demo/product-app/src/main/java/org/jboss/resteasy/example/oauth/ProductDatabaseClient.java 36(+0 -36)

integration/undertow/src/main/java/org/keycloak/adapters/undertow/RealmConfigurationLoader.java 97(+0 -97)

pom.xml 11(+9 -2)

services/pom.xml 16(+11 -5)

Details

diff --git a/core/src/main/java/org/keycloak/SkeletonKeySession.java b/core/src/main/java/org/keycloak/SkeletonKeySession.java
index 3f10c7e..6859283 100755
--- a/core/src/main/java/org/keycloak/SkeletonKeySession.java
+++ b/core/src/main/java/org/keycloak/SkeletonKeySession.java
@@ -34,4 +34,18 @@ public class SkeletonKeySession implements Serializable {
         return metadata;
     }
 
+    protected static ThreadLocal<SkeletonKeySession> local = new ThreadLocal<SkeletonKeySession>();
+
+    public static void pushContext(SkeletonKeySession session) {
+        local.set(session);
+    }
+
+    public static void clearContext() {
+        local.set(null);
+    }
+
+    public static SkeletonKeySession getContext() {
+        return local.get();
+    }
+
 }
diff --git a/core/src/main/java/org/keycloak/util/Encode.java b/core/src/main/java/org/keycloak/util/Encode.java
new file mode 100755
index 0000000..341f0df
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/Encode.java
@@ -0,0 +1,526 @@
+package org.keycloak.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Encode
+{
+   private static final String UTF_8 = "UTF-8";
+
+   private static final Pattern PARAM_REPLACEMENT = Pattern.compile("_resteasy_uri_parameter");
+
+   private static final String[] pathEncoding = new String[128];
+   private static final String[] pathSegmentEncoding = new String[128];
+   private static final String[] matrixParameterEncoding = new String[128];
+   private static final String[] queryNameValueEncoding = new String[128];
+   private static final String[] queryStringEncoding = new String[128];
+
+   static
+   {
+      /*
+       * Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>.  PCHAR is allowed allong with '/'
+       *
+       * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+       * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+                     / "*" / "+" / "," / ";" / "="
+       * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+       *
+       */
+      for (int i = 0; i < 128; i++)
+      {
+         if (i >= 'a' && i <= 'z') continue;
+         if (i >= 'A' && i <= 'Z') continue;
+         if (i >= '0' && i <= '9') continue;
+         switch ((char) i)
+         {
+            case '-':
+            case '.':
+            case '_':
+            case '~':
+            case '!':
+            case '$':
+            case '&':
+            case '\'':
+            case '(':
+            case ')':
+            case '*':
+            case '+':
+            case ',':
+            case '/':
+            case ';':
+            case '=':
+            case ':':
+            case '@':
+               continue;
+         }
+         StringBuffer sb = new StringBuffer();
+         sb.append((char) i);
+         pathEncoding[i] = URLEncoder.encode(sb.toString());
+      }
+      pathEncoding[' '] = "%20";
+      System.arraycopy(pathEncoding, 0, matrixParameterEncoding, 0, pathEncoding.length);
+      matrixParameterEncoding[';'] = "%3B";
+      matrixParameterEncoding['='] = "%3D";
+      matrixParameterEncoding['/'] = "%2F"; // RESTEASY-729
+      System.arraycopy(pathEncoding, 0, pathSegmentEncoding, 0, pathEncoding.length);
+      pathSegmentEncoding['/'] = "%2F";
+      /*
+       * Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
+       *
+       * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+       * space encoded as '+'
+       *
+       */
+      for (int i = 0; i < 128; i++)
+      {
+         if (i >= 'a' && i <= 'z') continue;
+         if (i >= 'A' && i <= 'Z') continue;
+         if (i >= '0' && i <= '9') continue;
+         switch ((char) i)
+         {
+            case '-':
+            case '.':
+            case '_':
+            case '~':
+            case '?':
+               continue;
+            case ' ':
+               queryNameValueEncoding[i] = "+";
+               continue;
+         }
+         StringBuffer sb = new StringBuffer();
+         sb.append((char) i);
+         queryNameValueEncoding[i] = URLEncoder.encode(sb.toString());
+      }
+
+      /*
+       * query       = *( pchar / "/" / "?" )
+
+       */
+      for (int i = 0; i < 128; i++)
+      {
+         if (i >= 'a' && i <= 'z') continue;
+         if (i >= 'A' && i <= 'Z') continue;
+         if (i >= '0' && i <= '9') continue;
+         switch ((char) i)
+         {
+            case '-':
+            case '.':
+            case '_':
+            case '~':
+            case '!':
+            case '$':
+            case '&':
+            case '\'':
+            case '(':
+            case ')':
+            case '*':
+            case '+':
+            case ',':
+            case ';':
+            case '=':
+            case ':':
+            case '@':
+            case '?':
+            case '/':
+               continue;
+            case ' ':
+               queryStringEncoding[i] = "%20";
+               continue;
+         }
+         StringBuffer sb = new StringBuffer();
+         sb.append((char) i);
+         queryStringEncoding[i] = URLEncoder.encode(sb.toString());
+      }
+   }
+
+   /**
+    * Keep encoded values "%..." and template parameters intact.
+    */
+   public static String encodeQueryString(String value)
+   {
+      return encodeValue(value, queryStringEncoding);
+   }
+
+   /**
+    * Keep encoded values "%...", matrix parameters, template parameters, and '/' characters intact.
+    */
+   public static String encodePath(String value)
+   {
+      return encodeValue(value, pathEncoding);
+   }
+
+   /**
+    * Keep encoded values "%...", matrix parameters and template parameters intact.
+    */
+   public static String encodePathSegment(String value)
+   {
+      return encodeValue(value, pathSegmentEncoding);
+   }
+
+   /**
+    * Keep encoded values "%..." and template parameters intact.
+    */
+   public static String encodeFragment(String value)
+   {
+      return encodeValue(value, queryNameValueEncoding);
+   }
+
+   /**
+    * Keep encoded values "%..." and template parameters intact.
+    */
+   public static String encodeMatrixParam(String value)
+   {
+      return encodeValue(value, matrixParameterEncoding);
+   }
+
+   /**
+    * Keep encoded values "%..." and template parameters intact.
+    */
+   public static String encodeQueryParam(String value)
+   {
+      return encodeValue(value, queryNameValueEncoding);
+   }
+
+   //private static final Pattern nonCodes = Pattern.compile("%([^a-fA-F0-9]|$)");
+   private static final Pattern nonCodes = Pattern.compile("%([^a-fA-F0-9]|[a-fA-F0-9]$|$|[a-fA-F0-9][^a-fA-F0-9])");
+   private static final Pattern encodedChars = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])");
+   private static final Pattern encodedCharsMulti = Pattern.compile("((%[a-fA-F0-9][a-fA-F0-9])+)");
+
+   public static String decodePath(String path)
+   {
+      Matcher matcher = encodedCharsMulti.matcher(path);
+      StringBuffer buf = new StringBuffer();
+      CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();
+      while (matcher.find())
+      {
+         decoder.reset();
+         String decoded = decodeBytes(matcher.group(1), decoder);
+         decoded = decoded.replace("\\", "\\\\");
+         decoded = decoded.replace("$", "\\$");
+         matcher.appendReplacement(buf, decoded);
+      }
+      matcher.appendTail(buf);
+      return buf.toString();
+   }
+
+   private static String decodeBytes(String enc, CharsetDecoder decoder)
+   {
+      Matcher matcher = encodedChars.matcher(enc);
+      StringBuffer buf = new StringBuffer();
+      ByteBuffer bytes = ByteBuffer.allocate(enc.length() / 3);
+      while (matcher.find())
+      {
+         int b = Integer.parseInt(matcher.group(1), 16);
+         bytes.put((byte) b);
+      }
+      bytes.flip();
+      try
+      {
+         return decoder.decode(bytes).toString();
+      }
+      catch (CharacterCodingException e)
+      {
+         throw new RuntimeException(e);
+      }
+   }
+
+   /**
+    * Encode '%' if it is not an encoding sequence
+    *
+    * @param string
+    * @return
+    */
+   public static String encodeNonCodes(String string)
+   {
+      Matcher matcher = nonCodes.matcher(string);
+      StringBuffer buf = new StringBuffer();
+
+
+      // FYI: we do not use the no-arg matcher.find()
+      //      coupled with matcher.appendReplacement()
+      //      because the matched text may contain
+      //      a second % and we must make sure we
+      //      encode it (if necessary).
+      int idx = 0;
+      while (matcher.find(idx))
+      {
+         int start = matcher.start();
+         buf.append(string.substring(idx, start));
+         buf.append("%25");
+         idx = start + 1;
+      }
+      buf.append(string.substring(idx));
+      return buf.toString();
+   }
+
+   public static boolean savePathParams(String segment, StringBuffer newSegment, List<String> params)
+   {
+      boolean foundParam = false;
+      // Regular expressions can have '{' and '}' characters.  Replace them to do match
+      segment = PathHelper.replaceEnclosedCurlyBraces(segment);
+      Matcher matcher = PathHelper.URI_TEMPLATE_PATTERN.matcher(segment);
+      while (matcher.find())
+      {
+         foundParam = true;
+         String group = matcher.group();
+         // Regular expressions can have '{' and '}' characters.  Recover earlier replacement
+         params.add(PathHelper.recoverEnclosedCurlyBraces(group));
+         matcher.appendReplacement(newSegment, "_resteasy_uri_parameter");
+      }
+      matcher.appendTail(newSegment);
+      return foundParam;
+   }
+
+   /**
+    * Keep encoded values "%..." and template parameters intact i.e. "{x}"
+    *
+    * @param segment
+    * @param encoding
+    * @return
+    */
+   public static String encodeValue(String segment, String[] encoding)
+   {
+      ArrayList<String> params = new ArrayList<String>();
+      boolean foundParam = false;
+      StringBuffer newSegment = new StringBuffer();
+      if (savePathParams(segment, newSegment, params))
+      {
+         foundParam = true;
+         segment = newSegment.toString();
+      }
+      String result = encodeFromArray(segment, encoding, false);
+      result = encodeNonCodes(result);
+      segment = result;
+      if (foundParam)
+      {
+         segment = pathParamReplacement(segment, params);
+      }
+      return segment;
+   }
+
+   /**
+    * Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>.  PCHAR is allowed allong with '/'
+    * <p/>
+    * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+    * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+    * / "*" / "+" / "," / ";" / "="
+    * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+    */
+   public static String encodePathAsIs(String segment)
+   {
+      return encodeFromArray(segment, pathEncoding, true);
+   }
+
+   /**
+    * Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
+    *
+    * @param segment
+    * @return
+    */
+   public static String encodePathSaveEncodings(String segment)
+   {
+      String result = encodeFromArray(segment, pathEncoding, false);
+      result = encodeNonCodes(result);
+      return result;
+   }
+
+   /**
+    * Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>.  PCHAR is allowed allong with '/'
+    * <p/>
+    * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+    * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+    * / "*" / "+" / "," / ";" / "="
+    * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+    */
+   public static String encodePathSegmentAsIs(String segment)
+   {
+      return encodeFromArray(segment, pathSegmentEncoding, true);
+   }
+
+   /**
+    * Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
+    *
+    * @param segment
+    * @return
+    */
+   public static String encodePathSegmentSaveEncodings(String segment)
+   {
+      String result = encodeFromArray(segment, pathSegmentEncoding, false);
+      result = encodeNonCodes(result);
+      return result;
+   }
+
+
+   /**
+    * Encodes everything of a query parameter name or value.
+    *
+    * @param nameOrValue
+    * @return
+    */
+   public static String encodeQueryParamAsIs(String nameOrValue)
+   {
+      return encodeFromArray(nameOrValue, queryNameValueEncoding, true);
+   }
+
+   /**
+    * Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
+    *
+    * @param segment
+    * @return
+    */
+   public static String encodeQueryParamSaveEncodings(String segment)
+   {
+      String result = encodeFromArray(segment, queryNameValueEncoding, false);
+      result = encodeNonCodes(result);
+      return result;
+   }
+
+   public static String encodeFragmentAsIs(String nameOrValue)
+   {
+      return encodeFromArray(nameOrValue, queryNameValueEncoding, true);
+   }
+
+   protected static String encodeFromArray(String segment, String[] encodingMap, boolean encodePercent)
+   {
+      StringBuffer result = new StringBuffer();
+      for (int i = 0; i < segment.length(); i++)
+      {
+         if (!encodePercent && segment.charAt(i) == '%')
+         {
+            result.append(segment.charAt(i));
+            continue;
+         }
+         int idx = segment.charAt(i);
+         String encoding = encode(idx, encodingMap);
+         if (encoding == null)
+         {
+            result.append(segment.charAt(i));
+         }
+         else
+         {
+            result.append(encoding);
+         }
+      }
+      return result.toString();
+   }
+
+   /**
+    * @param zhar        integer representation of character
+    * @param encodingMap encoding map
+    * @return URL encoded character
+    */
+   private static String encode(int zhar, String[] encodingMap)
+   {
+      String encoded;
+      if (zhar < encodingMap.length)
+      {
+         encoded = encodingMap[zhar];
+      }
+      else
+      {
+         try
+         {
+            encoded = URLEncoder.encode(Character.toString((char) zhar), UTF_8);
+         }
+         catch (UnsupportedEncodingException e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      return encoded;
+   }
+
+   public static String pathParamReplacement(String segment, List<String> params)
+   {
+      StringBuffer newSegment = new StringBuffer();
+      Matcher matcher = PARAM_REPLACEMENT.matcher(segment);
+      int i = 0;
+      while (matcher.find())
+      {
+         String replacement = params.get(i++);
+         // double encode slashes, so that slashes stay where they are 
+         replacement = replacement.replace("\\", "\\\\");
+         replacement = replacement.replace("$", "\\$");
+         matcher.appendReplacement(newSegment, replacement);
+      }
+      matcher.appendTail(newSegment);
+      segment = newSegment.toString();
+      return segment;
+   }
+
+   /**
+    * decode an encoded map
+    *
+    * @param map
+    * @return
+    */
+   public static MultivaluedHashMap<String, String> decode(MultivaluedHashMap<String, String> map)
+   {
+       MultivaluedHashMap<String, String> decoded = new MultivaluedHashMap<String, String>();
+      for (Map.Entry<String, List<String>> entry : map.entrySet())
+      {
+         List<String> values = entry.getValue();
+         for (String value : values)
+         {
+            try
+            {
+               decoded.add(URLDecoder.decode(entry.getKey(), UTF_8), URLDecoder.decode(value, UTF_8));
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               throw new RuntimeException(e);
+            }
+         }
+      }
+      return decoded;
+   }
+
+   public static MultivaluedHashMap<String, String> encode(MultivaluedHashMap<String, String> map)
+   {
+       MultivaluedHashMap<String, String> decoded = new MultivaluedHashMap<String, String>();
+      for (Map.Entry<String, List<String>> entry : map.entrySet())
+      {
+         List<String> values = entry.getValue();
+         for (String value : values)
+         {
+            try
+            {
+               decoded.add(URLEncoder.encode(entry.getKey(), UTF_8), URLEncoder.encode(value, UTF_8));
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               throw new RuntimeException(e);
+            }
+         }
+      }
+      return decoded;
+   }
+
+   public static String decode(String string)
+   {
+      try
+      {
+         return URLDecoder.decode(string, UTF_8);
+      }
+      catch (UnsupportedEncodingException e)
+      {
+         throw new RuntimeException(e);
+      }
+   }
+
+}
diff --git a/core/src/main/java/org/keycloak/util/KeycloakUriBuilder.java b/core/src/main/java/org/keycloak/util/KeycloakUriBuilder.java
new file mode 100755
index 0000000..111c4a4
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/KeycloakUriBuilder.java
@@ -0,0 +1,717 @@
+package org.keycloak.util;
+
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakUriBuilder {
+
+    private String host;
+    private String scheme;
+    private int port = -1;
+
+    private String userInfo;
+    private String path;
+    private String query;
+    private String fragment;
+    private String ssp;
+    private String authority;
+
+    public static KeycloakUriBuilder fromUri(URI uri) {
+        return new KeycloakUriBuilder().uri(uri);
+    }
+
+    public static KeycloakUriBuilder fromUri(String uriTemplate) {
+        return new KeycloakUriBuilder().uri(uriTemplate);
+    }
+
+    public static KeycloakUriBuilder fromPath(String path) throws IllegalArgumentException {
+        return new KeycloakUriBuilder().path(path);
+    }
+
+
+    public KeycloakUriBuilder clone() {
+        KeycloakUriBuilder impl = new KeycloakUriBuilder();
+        impl.host = host;
+        impl.scheme = scheme;
+        impl.port = port;
+        impl.userInfo = userInfo;
+        impl.path = path;
+        impl.query = query;
+        impl.fragment = fragment;
+        impl.ssp = ssp;
+        impl.authority = authority;
+
+        return impl;
+    }
+
+    public static final Pattern opaqueUri = Pattern.compile("^([^:/?#]+):([^/].*)");
+    public static final Pattern hierarchicalUri = Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?");
+    private static final Pattern hostPortPattern = Pattern.compile("([^/:]+):(\\d+)");
+
+    public static boolean compare(String s1, String s2) {
+        if (s1 == s2) return true;
+        if (s1 == null || s2 == null) return false;
+        return s1.equals(s2);
+    }
+
+    public static URI relativize(URI from, URI to) {
+        if (!compare(from.getScheme(), to.getScheme())) return to;
+        if (!compare(from.getHost(), to.getHost())) return to;
+        if (from.getPort() != to.getPort()) return to;
+        if (from.getPath() == null && to.getPath() == null) return URI.create("");
+        else if (from.getPath() == null) return URI.create(to.getPath());
+        else if (to.getPath() == null) return to;
+
+
+        String fromPath = from.getPath();
+        if (fromPath.startsWith("/")) fromPath = fromPath.substring(1);
+        String[] fsplit = fromPath.split("/");
+        String toPath = to.getPath();
+        if (toPath.startsWith("/")) toPath = toPath.substring(1);
+        String[] tsplit = toPath.split("/");
+
+        int f = 0;
+
+        for (; f < fsplit.length && f < tsplit.length; f++) {
+            if (!fsplit[f].equals(tsplit[f])) break;
+        }
+
+        KeycloakUriBuilder builder = KeycloakUriBuilder.fromPath("");
+        for (int i = f; i < fsplit.length; i++) builder.path("..");
+        for (int i = f; i < tsplit.length; i++) builder.path(tsplit[i]);
+        return builder.build();
+    }
+
+    /**
+     * You may put path parameters anywhere within the uriTemplate except port
+     *
+     * @param uriTemplate
+     * @return
+     */
+    public static KeycloakUriBuilder fromTemplate(String uriTemplate) {
+        KeycloakUriBuilder impl = new KeycloakUriBuilder();
+        impl.uriTemplate(uriTemplate);
+        return impl;
+    }
+
+    /**
+     * You may put path parameters anywhere within the uriTemplate except port
+     *
+     * @param uriTemplate
+     * @return
+     */
+    public KeycloakUriBuilder uriTemplate(String uriTemplate) {
+        if (uriTemplate == null) throw new IllegalArgumentException("uriTemplate parameter is null");
+        Matcher opaque = opaqueUri.matcher(uriTemplate);
+        if (opaque.matches()) {
+            this.authority = null;
+            this.host = null;
+            this.port = -1;
+            this.userInfo = null;
+            this.query = null;
+            this.scheme = opaque.group(1);
+            this.ssp = opaque.group(2);
+            return this;
+        } else {
+            Matcher match = hierarchicalUri.matcher(uriTemplate);
+            if (match.matches()) {
+                ssp = null;
+                return parseHierarchicalUri(uriTemplate, match);
+            }
+        }
+        throw new IllegalArgumentException("Illegal uri template: " + uriTemplate);
+    }
+
+    protected KeycloakUriBuilder parseHierarchicalUri(String uriTemplate, Matcher match) {
+        boolean scheme = match.group(2) != null;
+        if (scheme) this.scheme = match.group(2);
+        String authority = match.group(4);
+        if (authority != null) {
+            this.authority = null;
+            String host = match.group(4);
+            int at = host.indexOf('@');
+            if (at > -1) {
+                String user = host.substring(0, at);
+                host = host.substring(at + 1);
+                this.userInfo = user;
+            }
+            Matcher hostPortMatch = hostPortPattern.matcher(host);
+            if (hostPortMatch.matches()) {
+                this.host = hostPortMatch.group(1);
+                int val = 0;
+                try {
+                    this.port = Integer.parseInt(hostPortMatch.group(2));
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Illegal uri template: " + uriTemplate, e);
+                }
+            } else {
+                this.host = host;
+            }
+        }
+        if (match.group(5) != null) {
+            String group = match.group(5);
+            if (!scheme && !"".equals(group) && !group.startsWith("/") && group.indexOf(':') > -1)
+                throw new IllegalArgumentException("Illegal uri template: " + uriTemplate);
+            if (!"".equals(group)) replacePath(group);
+        }
+        if (match.group(7) != null) replaceQuery(match.group(7));
+        if (match.group(9) != null) fragment(match.group(9));
+        return this;
+    }
+
+    public KeycloakUriBuilder uri(String uriTemplate) throws IllegalArgumentException {
+        return uriTemplate(uriTemplate);
+    }
+
+    public KeycloakUriBuilder uri(URI uri) throws IllegalArgumentException {
+        if (uri == null) throw new IllegalArgumentException("URI was null");
+
+        if (uri.getRawFragment() != null) fragment = uri.getRawFragment();
+
+        if (uri.isOpaque()) {
+            scheme = uri.getScheme();
+            ssp = uri.getRawSchemeSpecificPart();
+            return this;
+        }
+
+        if (uri.getScheme() == null) {
+            if (ssp != null) {
+                if (uri.getRawSchemeSpecificPart() != null) {
+                    ssp = uri.getRawSchemeSpecificPart();
+                    return this;
+                }
+            }
+        } else {
+            scheme = uri.getScheme();
+        }
+
+        ssp = null;
+        if (uri.getRawAuthority() != null) {
+            if (uri.getRawUserInfo() == null && uri.getHost() == null && uri.getPort() == -1) {
+                authority = uri.getRawAuthority();
+                userInfo = null;
+                host = null;
+                port = -1;
+            } else {
+                authority = null;
+                if (uri.getRawUserInfo() != null) {
+                    userInfo = uri.getRawUserInfo();
+                }
+                if (uri.getHost() != null) {
+                    host = uri.getHost();
+                }
+                if (uri.getPort() != -1) {
+                    port = uri.getPort();
+                }
+            }
+        }
+
+        if (uri.getRawPath() != null && uri.getRawPath().length() > 0) {
+            path = uri.getRawPath();
+        }
+        if (uri.getRawQuery() != null && uri.getRawQuery().length() > 0) {
+            query = uri.getRawQuery();
+        }
+
+        return this;
+    }
+
+    public KeycloakUriBuilder scheme(String scheme) throws IllegalArgumentException {
+        this.scheme = scheme;
+        return this;
+    }
+
+    public KeycloakUriBuilder schemeSpecificPart(String ssp) throws IllegalArgumentException {
+        if (ssp == null) throw new IllegalArgumentException("schemeSpecificPart was null");
+
+        StringBuilder sb = new StringBuilder();
+        if (scheme != null) sb.append(scheme).append(':');
+        if (ssp != null)
+            sb.append(ssp);
+        if (fragment != null && fragment.length() > 0) sb.append('#').append(fragment);
+        URI uri = URI.create(sb.toString());
+
+        if (uri.getRawSchemeSpecificPart() != null && uri.getRawPath() == null) {
+            this.ssp = uri.getRawSchemeSpecificPart();
+        } else {
+            this.ssp = null;
+            userInfo = uri.getRawUserInfo();
+            host = uri.getHost();
+            port = uri.getPort();
+            path = uri.getRawPath();
+            query = uri.getRawQuery();
+
+        }
+        return this;
+
+    }
+
+    public KeycloakUriBuilder userInfo(String ui) {
+        this.userInfo = ui;
+        return this;
+    }
+
+    public KeycloakUriBuilder host(String host) throws IllegalArgumentException {
+        if (host != null && host.equals("")) throw new IllegalArgumentException("invalid host");
+        this.host = host;
+        return this;
+    }
+
+    public KeycloakUriBuilder port(int port) throws IllegalArgumentException {
+        if (port < -1) throw new IllegalArgumentException("Invalid port value");
+        this.port = port;
+        return this;
+    }
+
+    protected static String paths(boolean encode, String basePath, String... segments) {
+        String path = basePath;
+        if (path == null) path = "";
+        for (String segment : segments) {
+            if ("".equals(segment)) continue;
+            if (path.endsWith("/")) {
+                if (segment.startsWith("/")) {
+                    segment = segment.substring(1);
+                    if ("".equals(segment)) continue;
+                }
+                if (encode) segment = Encode.encodePath(segment);
+                path += segment;
+            } else {
+                if (encode) segment = Encode.encodePath(segment);
+                if ("".equals(path)) {
+                    path = segment;
+                } else if (segment.startsWith("/")) {
+                    path += segment;
+                } else {
+                    path += "/" + segment;
+                }
+            }
+
+        }
+        return path;
+    }
+
+    public KeycloakUriBuilder path(String segment) throws IllegalArgumentException {
+        if (segment == null) throw new IllegalArgumentException("path was null");
+        path = paths(true, path, segment);
+        return this;
+    }
+
+    public KeycloakUriBuilder replaceMatrix(String matrix) throws IllegalArgumentException {
+        if (matrix == null) matrix = "";
+        if (!matrix.startsWith(";")) matrix = ";" + matrix;
+        matrix = Encode.encodePath(matrix);
+        if (path == null) {
+            path = matrix;
+        } else {
+            int start = path.lastIndexOf('/');
+            if (start < 0) start = 0;
+            int matrixIndex = path.indexOf(';', start);
+            if (matrixIndex > -1) path = path.substring(0, matrixIndex) + matrix;
+            else path += matrix;
+
+        }
+        return this;
+    }
+
+    public KeycloakUriBuilder replaceQuery(String query) throws IllegalArgumentException {
+        if (query == null || query.length() == 0) {
+            this.query = null;
+            return this;
+        }
+        this.query = Encode.encodeQueryString(query);
+        return this;
+    }
+
+    public KeycloakUriBuilder fragment(String fragment) throws IllegalArgumentException {
+        if (fragment == null) {
+            this.fragment = null;
+            return this;
+        }
+        this.fragment = Encode.encodeFragment(fragment);
+        return this;
+    }
+
+    /**
+     * Only replace path params in path of URI.  This changes state of URIBuilder.
+     *
+     * @param name
+     * @param value
+     * @param isEncoded
+     * @return
+     */
+    public KeycloakUriBuilder substitutePathParam(String name, Object value, boolean isEncoded) {
+        if (path != null) {
+            StringBuffer buffer = new StringBuffer();
+            replacePathParameter(name, value.toString(), isEncoded, path, buffer, false);
+            path = buffer.toString();
+        }
+        return this;
+    }
+
+    public URI buildFromMap(Map<String, ? extends Object> values) throws IllegalArgumentException {
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        return buildUriFromMap(values, false, true);
+    }
+
+    public URI buildFromEncodedMap(Map<String, ? extends Object> values) throws IllegalArgumentException {
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        return buildUriFromMap(values, true, false);
+    }
+
+    public URI buildFromMap(Map<String, ?> values, boolean encodeSlashInPath) throws IllegalArgumentException {
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        return buildUriFromMap(values, false, encodeSlashInPath);
+    }
+
+    protected URI buildUriFromMap(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean encodeSlash) throws IllegalArgumentException {
+        String buf = buildString(paramMap, fromEncodedMap, false, encodeSlash);
+        try {
+            return URI.create(buf);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create URI: " + buf, e);
+        }
+    }
+
+    private String buildString(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, boolean encodeSlash) {
+        for (Map.Entry<String, ? extends Object> entry : paramMap.entrySet()) {
+            if (entry.getKey() == null) throw new IllegalArgumentException("map key is null");
+            if (entry.getValue() == null) throw new IllegalArgumentException("map value is null");
+        }
+        StringBuffer buffer = new StringBuffer();
+
+        if (scheme != null)
+            replaceParameter(paramMap, fromEncodedMap, isTemplate, scheme, buffer, encodeSlash).append(":");
+        if (ssp != null) {
+            buffer.append(ssp);
+        } else if (userInfo != null || host != null || port != -1) {
+            buffer.append("//");
+            if (userInfo != null)
+                replaceParameter(paramMap, fromEncodedMap, isTemplate, userInfo, buffer, encodeSlash).append("@");
+            if (host != null) {
+                if ("".equals(host)) throw new RuntimeException("empty host name");
+                replaceParameter(paramMap, fromEncodedMap, isTemplate, host, buffer, encodeSlash);
+            }
+            if (port != -1) buffer.append(":").append(Integer.toString(port));
+        } else if (authority != null) {
+            buffer.append("//");
+            replaceParameter(paramMap, fromEncodedMap, isTemplate, authority, buffer, encodeSlash);
+        }
+        if (path != null) {
+            StringBuffer tmp = new StringBuffer();
+            replaceParameter(paramMap, fromEncodedMap, isTemplate, path, tmp, encodeSlash);
+            String tmpPath = tmp.toString();
+            if (userInfo != null || host != null) {
+                if (!tmpPath.startsWith("/")) buffer.append("/");
+            }
+            buffer.append(tmpPath);
+        }
+        if (query != null) {
+            buffer.append("?");
+            replaceQueryStringParameter(paramMap, fromEncodedMap, isTemplate, query, buffer);
+        }
+        if (fragment != null) {
+            buffer.append("#");
+            replaceParameter(paramMap, fromEncodedMap, isTemplate, fragment, buffer, encodeSlash);
+        }
+        return buffer.toString();
+    }
+
+    protected StringBuffer replacePathParameter(String name, String value, boolean isEncoded, String string, StringBuffer buffer, boolean encodeSlash) {
+        Matcher matcher = createUriParamMatcher(string);
+        while (matcher.find()) {
+            String param = matcher.group(1);
+            if (!param.equals(name)) continue;
+            if (!isEncoded) {
+                if (encodeSlash) value = Encode.encodePath(value);
+                else value = Encode.encodePathSegment(value);
+
+            } else {
+                value = Encode.encodeNonCodes(value);
+            }
+            // if there is a $ then we must backslash it or it will screw up regex group substitution
+            value = value.replace("$", "\\$");
+            matcher.appendReplacement(buffer, value);
+        }
+        matcher.appendTail(buffer);
+        return buffer;
+    }
+
+    public static Matcher createUriParamMatcher(String string) {
+        Matcher matcher = PathHelper.URI_PARAM_PATTERN.matcher(PathHelper.replaceEnclosedCurlyBraces(string));
+        return matcher;
+    }
+
+    protected StringBuffer replaceParameter(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, String string, StringBuffer buffer, boolean encodeSlash) {
+        Matcher matcher = createUriParamMatcher(string);
+        while (matcher.find()) {
+            String param = matcher.group(1);
+            Object valObj = paramMap.get(param);
+            if (valObj == null && !isTemplate) {
+                throw new IllegalArgumentException("NULL value for template parameter: " + param);
+            } else if (valObj == null && isTemplate) {
+                matcher.appendReplacement(buffer, matcher.group());
+                continue;
+            }
+            String value = valObj.toString();
+            if (value != null) {
+                if (!fromEncodedMap) {
+                    if (encodeSlash) value = Encode.encodePathSegmentAsIs(value);
+                    else value = Encode.encodePathAsIs(value);
+                } else {
+                    if (encodeSlash) value = Encode.encodePathSegmentSaveEncodings(value);
+                    else value = Encode.encodePathSaveEncodings(value);
+                }
+                matcher.appendReplacement(buffer, Matcher.quoteReplacement(value));
+            } else {
+                throw new IllegalArgumentException("path param " + param + " has not been provided by the parameter map");
+            }
+        }
+        matcher.appendTail(buffer);
+        return buffer;
+    }
+
+    protected StringBuffer replaceQueryStringParameter(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, String string, StringBuffer buffer) {
+        Matcher matcher = createUriParamMatcher(string);
+        while (matcher.find()) {
+            String param = matcher.group(1);
+            Object valObj = paramMap.get(param);
+            if (valObj == null && !isTemplate) {
+                throw new IllegalArgumentException("NULL value for template parameter: " + param);
+            } else if (valObj == null && isTemplate) {
+                matcher.appendReplacement(buffer, matcher.group());
+                continue;
+            }
+            String value = valObj.toString();
+            if (value != null) {
+                if (!fromEncodedMap) {
+                    value = Encode.encodeQueryParamAsIs(value);
+                } else {
+                    value = Encode.encodeQueryParamSaveEncodings(value);
+                }
+                matcher.appendReplacement(buffer, value);
+            } else {
+                throw new IllegalArgumentException("path param " + param + " has not been provided by the parameter map");
+            }
+        }
+        matcher.appendTail(buffer);
+        return buffer;
+    }
+
+    /**
+     * Return a unique order list of path params
+     *
+     * @return
+     */
+    public List<String> getPathParamNamesInDeclarationOrder() {
+        List<String> params = new ArrayList<String>();
+        HashSet<String> set = new HashSet<String>();
+        if (scheme != null) addToPathParamList(params, set, scheme);
+        if (userInfo != null) addToPathParamList(params, set, userInfo);
+        if (host != null) addToPathParamList(params, set, host);
+        if (path != null) addToPathParamList(params, set, path);
+        if (query != null) addToPathParamList(params, set, query);
+        if (fragment != null) addToPathParamList(params, set, fragment);
+
+        return params;
+    }
+
+    private void addToPathParamList(List<String> params, HashSet<String> set, String string) {
+        Matcher matcher = PathHelper.URI_PARAM_PATTERN.matcher(PathHelper.replaceEnclosedCurlyBraces(string));
+        while (matcher.find()) {
+            String param = matcher.group(1);
+            if (set.contains(param)) continue;
+            else {
+                set.add(param);
+                params.add(param);
+            }
+        }
+    }
+
+    public URI build(Object... values) throws IllegalArgumentException {
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        return buildFromValues(true, false, values);
+    }
+
+    protected URI buildFromValues(boolean encodeSlash, boolean encoded, Object... values) {
+        List<String> params = getPathParamNamesInDeclarationOrder();
+        if (values.length < params.size())
+            throw new IllegalArgumentException("You did not supply enough values to fill path parameters");
+
+        Map<String, Object> pathParams = new HashMap<String, Object>();
+
+
+        for (int i = 0; i < params.size(); i++) {
+            String pathParam = params.get(i);
+            Object val = values[i];
+            if (val == null) throw new IllegalArgumentException("A value was null");
+            pathParams.put(pathParam, val.toString());
+        }
+        String buf = null;
+        try {
+            buf = buildString(pathParams, encoded, false, encodeSlash);
+            return new URI(buf);
+            //return URI.create(buf);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create URI: " + buf, e);
+        }
+    }
+
+    public KeycloakUriBuilder matrixParam(String name, Object... values) throws IllegalArgumentException {
+        if (name == null) throw new IllegalArgumentException("name parameter is null");
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        if (path == null) path = "";
+        for (Object val : values) {
+            if (val == null) throw new IllegalArgumentException("null value");
+            path += ";" + Encode.encodeMatrixParam(name) + "=" + Encode.encodeMatrixParam(val.toString());
+        }
+        return this;
+    }
+
+    private static final Pattern PARAM_REPLACEMENT = Pattern.compile("_resteasy_uri_parameter");
+
+
+    public KeycloakUriBuilder queryParam(String name, Object... values) throws IllegalArgumentException {
+        if (name == null) throw new IllegalArgumentException("name parameter is null");
+        if (values == null) throw new IllegalArgumentException("values parameter is null");
+        for (Object value : values) {
+            if (value == null) throw new IllegalArgumentException("A passed in value was null");
+            if (query == null) query = "";
+            else query += "&";
+            query += Encode.encodeQueryParam(name) + "=" + Encode.encodeQueryParam(value.toString());
+        }
+        return this;
+    }
+
+    public KeycloakUriBuilder replaceQueryParam(String name, Object... values) throws IllegalArgumentException {
+        if (name == null) throw new IllegalArgumentException("name parameter is null");
+        if (query == null || query.equals("")) {
+            if (values != null) return queryParam(name, values);
+            return this;
+        }
+
+        String[] params = query.split("&");
+        query = null;
+
+        String replacedName = Encode.encodeQueryParam(name);
+
+
+        for (String param : params) {
+            int pos = param.indexOf('=');
+            if (pos >= 0) {
+                String paramName = param.substring(0, pos);
+                if (paramName.equals(replacedName)) continue;
+            } else {
+                if (param.equals(replacedName)) continue;
+            }
+            if (query == null) query = "";
+            else query += "&";
+            query += param;
+        }
+        // don't set values if values is null
+        if (values == null) return this;
+        // don't set values if values is null
+        if (values == null) return this;
+        return queryParam(name, values);
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public String getScheme() {
+        return scheme;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public String getUserInfo() {
+        return userInfo;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public String getFragment() {
+        return fragment;
+    }
+
+    public KeycloakUriBuilder segment(String... segments) throws IllegalArgumentException {
+        if (segments == null) throw new IllegalArgumentException("segments parameter was null");
+        for (String segment : segments) {
+            if (segment == null) throw new IllegalArgumentException("A segment is null");
+            path(Encode.encodePathSegment(segment));
+        }
+        return this;
+    }
+
+    public KeycloakUriBuilder replacePath(String path) {
+        if (path == null) {
+            this.path = null;
+            return this;
+        }
+        this.path = Encode.encodePath(path);
+        return this;
+    }
+
+    public URI build(Object[] values, boolean encodeSlashInPath) throws IllegalArgumentException {
+        if (values == null) throw new IllegalArgumentException("values param is null");
+        return buildFromValues(encodeSlashInPath, false, values);
+    }
+
+    public String toTemplate() {
+        return buildString(new HashMap<String, Object>(), true, true, true);
+    }
+
+    public KeycloakUriBuilder resolveTemplate(String name, Object value) throws IllegalArgumentException {
+        if (name == null) throw new IllegalArgumentException("name param is null");
+        if (value == null) throw new IllegalArgumentException("value param is null");
+        HashMap<String, Object> vals = new HashMap<String, Object>();
+        vals.put(name, value);
+        return resolveTemplates(vals);
+    }
+
+    public KeycloakUriBuilder resolveTemplates(Map<String, Object> templateValues) throws IllegalArgumentException {
+        if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
+        String str = buildString(templateValues, false, true, true);
+        return fromTemplate(str);
+    }
+
+    public KeycloakUriBuilder resolveTemplate(String name, Object value, boolean encodeSlashInPath) throws IllegalArgumentException {
+        if (name == null) throw new IllegalArgumentException("name param is null");
+        if (value == null) throw new IllegalArgumentException("value param is null");
+        HashMap<String, Object> vals = new HashMap<String, Object>();
+        vals.put(name, value);
+        String str = buildString(vals, false, true, encodeSlashInPath);
+        return fromTemplate(str);
+    }
+
+    public KeycloakUriBuilder resolveTemplates(Map<String, Object> templateValues, boolean encodeSlashInPath) throws IllegalArgumentException {
+        if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
+        String str = buildString(templateValues, false, true, encodeSlashInPath);
+        return fromTemplate(str);
+    }
+
+    public KeycloakUriBuilder resolveTemplatesFromEncoded(Map<String, Object> templateValues) throws IllegalArgumentException {
+        if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
+        String str = buildString(templateValues, true, true, true);
+        return fromTemplate(str);
+    }
+}
diff --git a/core/src/main/java/org/keycloak/util/PathHelper.java b/core/src/main/java/org/keycloak/util/PathHelper.java
new file mode 100755
index 0000000..644f03e
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/PathHelper.java
@@ -0,0 +1,62 @@
+/**
+ *
+ */
+package org.keycloak.util;
+
+import java.util.regex.Pattern;
+
+
+/**
+ * A utility class for handling URI template parameters. As the Java
+ * regulare expressions package does not handle named groups, this
+ * class attempts to simulate that functionality by using groups.
+ *
+ * @author Ryan J. McDonough
+ * @author Bill Burke
+ * @since 1.0
+ *        Nov 8, 2006
+ */
+public class PathHelper
+{
+   public static final String URI_PARAM_NAME_REGEX = "\\w[\\w\\.-]*";
+   public static final String URI_PARAM_REGEX_REGEX = "[^{}][^{}]*";
+   public static final String URI_PARAM_REGEX = "\\{\\s*(" + URI_PARAM_NAME_REGEX + ")\\s*(:\\s*(" + URI_PARAM_REGEX_REGEX + "))?\\}";
+   public static final Pattern URI_PARAM_PATTERN = Pattern.compile(URI_PARAM_REGEX);
+
+   /**
+    * A regex pattern that searches for a URI template parameter in the form of {*}
+    */
+   public static final Pattern URI_TEMPLATE_PATTERN = Pattern.compile("(\\{([^}]+)\\})");
+
+   public static final char openCurlyReplacement = 6;
+   public static final char closeCurlyReplacement = 7;
+
+   public static String replaceEnclosedCurlyBraces(String str)
+   {
+      char[] chars = str.toCharArray();
+      int open = 0;
+      for (int i = 0; i < chars.length; i++)
+      {
+         if (chars[i] == '{')
+         {
+            if (open != 0) chars[i] = openCurlyReplacement;
+            open++;
+         }
+         else if (chars[i] == '}')
+         {
+            open--;
+            if (open != 0)
+            {
+               chars[i] = closeCurlyReplacement;
+            }
+         }
+      }
+      return new String(chars);
+   }
+
+   public static String recoverEnclosedCurlyBraces(String str)
+   {
+      return str.replace(openCurlyReplacement, '{').replace(closeCurlyReplacement, '}');
+   }
+
+}
\ No newline at end of file
diff --git a/examples/as7-eap-demo/customer-app/pom.xml b/examples/as7-eap-demo/customer-app/pom.xml
index 5d88ff3..3fe1702 100755
--- a/examples/as7-eap-demo/customer-app/pom.xml
+++ b/examples/as7-eap-demo/customer-app/pom.xml
@@ -29,26 +29,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core-jaxrs</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-adapter-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-as7-adapter</artifactId>
             <version>${project.version}</version>
diff --git a/examples/as7-eap-demo/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java b/examples/as7-eap-demo/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
new file mode 100755
index 0000000..6da7843
--- /dev/null
+++ b/examples/as7-eap-demo/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
@@ -0,0 +1,49 @@
+package org.keycloak.example;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.util.JsonSerialization;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CustomerDatabaseClient {
+
+    static class TypedList extends ArrayList<String> {}
+
+    public static List<String> getCustomers() {
+        SkeletonKeySession session = SkeletonKeySession.getContext();
+        HttpClient client = new HttpClientBuilder()
+                .trustStore(session.getMetadata().getTruststore())
+                .hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
+        try {
+            HttpGet get = new HttpGet("http://localhost:8080/database/customers");
+            get.addHeader("Authorization", "Bearer " + session.getTokenString());
+            try {
+                HttpResponse response = client.execute(get);
+                HttpEntity entity = response.getEntity();
+                InputStream is = entity.getContent();
+                try {
+                    return JsonSerialization.readValue(is, TypedList.class);
+                } finally {
+                    is.close();
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+}
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/admin/admin.jsp b/examples/as7-eap-demo/customer-app/src/main/webapp/admin/admin.jsp
old mode 100644
new mode 100755
index e132e37..39c2a43
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/admin/admin.jsp
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/admin/admin.jsp
@@ -2,7 +2,7 @@
  pageEncoding="ISO-8859-1"%>
 <html>
 <head>
-    <title>Customer Admin Iterface</title>
+    <title>Customer Admin Interface</title>
 </head>
 <body bgcolor="#E3F6CE">
 <h1>Customer Admin Interface</h1>
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
index 7eb5f58..344bd3e 100755
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
@@ -1,20 +1,22 @@
-<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
+<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
+<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
 <html>
 <head>
     <title>Customer View Page</title>
 </head>
 <body bgcolor="#E3F6CE">
 <%
-   String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
-                                     .queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
-   String acctUri =   UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/account").build().toString();
+    String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
+            .queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
+    String acctUri =   "http://localhost:8080/auth-server/rest/realms/demo/account";
 %>
 <p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a href="<%=acctUri%>">manage acct</a></p>
 User <b><%=request.getUserPrincipal().getName()%></b> made this request.
 <h2>Customer Listing</h2>
 <%
-java.util.List<String> list = org.jboss.resteasy.example.oauth.CustomerDatabaseClient.getCustomers(request);
+java.util.List<String> list = CustomerDatabaseClient.getCustomers();
 for (String cust : list)
 {
    out.print("<p>");
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 697d61c..c54e4ab 100755
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -2,9 +2,6 @@
     <deployment>
         <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
         <dependencies>
-            <module name="org.bouncycastle"/>
-            <module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
-            <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-web.xml b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-web.xml
index 3cec19c..a28a265 100755
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-web.xml
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/jboss-web.xml
@@ -1,5 +1,5 @@
 <jboss-web>
     <valve>
-        <class-name>org.keycloak.adapters.as7.OAuthManagedResourceValve</class-name>
+        <class-name>org.keycloak.adapters.as7.OAuthAuthenticatorValve</class-name>
     </valve>
 </jboss-web>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/database-service/pom.xml b/examples/as7-eap-demo/database-service/pom.xml
index 57ef592..fe9ea5a 100755
--- a/examples/as7-eap-demo/database-service/pom.xml
+++ b/examples/as7-eap-demo/database-service/pom.xml
@@ -30,24 +30,23 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core-jaxrs</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-adapter-core</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
         </dependency>
+
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-as7-adapter</artifactId>
             <version>${project.version}</version>
+            <!--
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.httpcomponents</groupId>
+                    <artifactId>httpclient</artifactId>
+                </exclusion>
+            </exclusions>
+            -->
         </dependency>
     </dependencies>
 
diff --git a/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 45b708c..c54e4ab 100755
--- a/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -2,7 +2,6 @@
     <deployment>
         <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
         <dependencies>
-            <module name="org.bouncycastle"/>
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/product-app/pom.xml b/examples/as7-eap-demo/product-app/pom.xml
index 5054870..6e8bf03 100755
--- a/examples/as7-eap-demo/product-app/pom.xml
+++ b/examples/as7-eap-demo/product-app/pom.xml
@@ -29,26 +29,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core-jaxrs</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-adapter-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-as7-adapter</artifactId>
             <version>${project.version}</version>
diff --git a/examples/as7-eap-demo/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/as7-eap-demo/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
new file mode 100755
index 0000000..61dcec6
--- /dev/null
+++ b/examples/as7-eap-demo/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -0,0 +1,49 @@
+package org.keycloak.example.oauth;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProductDatabaseClient
+{
+    static class TypedList extends ArrayList<String> {}
+
+    public static List<String> getProducts() {
+        SkeletonKeySession session = SkeletonKeySession.getContext();
+        HttpClient client = new HttpClientBuilder()
+                .trustStore(session.getMetadata().getTruststore())
+                .hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
+        try {
+            HttpGet get = new HttpGet("http://localhost:8080/database/products");
+            get.addHeader("Authorization", "Bearer " + session.getTokenString());
+            try {
+                HttpResponse response = client.execute(get);
+                HttpEntity entity = response.getEntity();
+                InputStream is = entity.getContent();
+                try {
+                    return JsonSerialization.readValue(is, TypedList.class);
+                } finally {
+                    is.close();
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+
+}
diff --git a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
index 88c6493..cd3d8d0 100755
--- a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
+++ b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
@@ -1,21 +1,23 @@
-<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
+<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %>
+<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
 <html>
 <head>
     <title>Product View Page</title>
 </head>
 <body bgcolor="#F5F6CE">
 <%
-   String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
+   String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
                                      .queryParam("redirect_uri", "http://localhost:8080/product-portal").build().toString();
-    String acctUri =   UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/account").build().toString();
+    String acctUri =   "http://localhost:8080/auth-server/rest/realms/demo/account";
 %>
 
 <p>Goto: <a href="http://localhost:8080/customer-portal">customers</a> | <a href="<%=logoutUri%>">logout</a> | <a href="<%=acctUri%>">manage acct</a></p>
 User <b><%=request.getUserPrincipal().getName()%></b> made this request.
 <h2>Product Listing</h2>
 <%
-java.util.List<String> list = org.jboss.resteasy.example.oauth.ProductDatabaseClient.getProducts(request);
+java.util.List<String> list = ProductDatabaseClient.getProducts();
 for (String cust : list)
 {
    out.print("<p>");
diff --git a/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/jboss-web.xml b/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/jboss-web.xml
index 3cec19c..a28a265 100755
--- a/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/jboss-web.xml
+++ b/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/jboss-web.xml
@@ -1,5 +1,5 @@
 <jboss-web>
     <valve>
-        <class-name>org.keycloak.adapters.as7.OAuthManagedResourceValve</class-name>
+        <class-name>org.keycloak.adapters.as7.OAuthAuthenticatorValve</class-name>
     </valve>
 </jboss-web>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/pom.xml b/examples/as7-eap-demo/third-party/pom.xml
index 04308a9..89372bc 100755
--- a/examples/as7-eap-demo/third-party/pom.xml
+++ b/examples/as7-eap-demo/third-party/pom.xml
@@ -22,18 +22,8 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-core-jaxrs</artifactId>
+            <artifactId>keycloak-servlet-oauth-client</artifactId>
             <version>${project.version}</version>
         </dependency>
     </dependencies>
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
old mode 100644
new mode 100755
index 63ad9d9..a64f674
--- a/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
@@ -1,3 +1,4 @@
+<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %>
 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
 <html>
@@ -7,7 +8,7 @@
 <body>
 <h2>Pulled Product Listing</h2>
 <%
-java.util.List<String> list = org.jboss.resteasy.example.oauth.ProductDatabaseClient.getProducts(request);
+java.util.List<String> list = ProductDatabaseClient.getProducts(request);
 for (String prod : list)
 {
    out.print("<p>");
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
old mode 100644
new mode 100755
index 35ff870..c74a9ae
--- a/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
@@ -1,3 +1,3 @@
-<%
-   org.jboss.resteasy.example.oauth.ProductDatabaseClient.redirect(request, response);
+<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %><%
+   ProductDatabaseClient.redirect(request, response);
 %>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 74f5dff..c54e4ab 100755
--- a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -2,8 +2,6 @@
     <deployment>
         <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
         <dependencies>
-            <module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
-            <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
index 501b203..958839d 100755
--- a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
@@ -7,7 +7,7 @@
 	<module-name>oauth-client</module-name>
 
     <listener>
-        <listener-class>org.jboss.resteasy.example.oauth.Bootstrap</listener-class>
+        <listener-class>org.keycloak.example.oauth.Bootstrap</listener-class>
     </listener>
     <!--
     <security-constraint>
diff --git a/integration/adapter-core/pom.xml b/integration/adapter-core/pom.xml
index 9cda78b..23d9114 100755
--- a/integration/adapter-core/pom.xml
+++ b/integration/adapter-core/pom.xml
@@ -22,14 +22,17 @@
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-core-asl</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-xc</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
@@ -37,13 +40,9 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-jaxrs</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.1.2</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfig.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfig.java
index ee038d8..5bdaf5b 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfig.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfig.java
@@ -21,7 +21,7 @@ public class AdapterConfig
     protected String resource;
     @JsonProperty("realm-public-key")
     protected String realmKey;
-   @JsonProperty("auth-url")
+    @JsonProperty("auth-url")
     protected String authUrl;
     @JsonProperty("code-url")
     protected String codeUrl;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
new file mode 100755
index 0000000..3f1d473
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java
@@ -0,0 +1,274 @@
+package org.keycloak.adapters;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
+import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.StrictHostnameVerifier;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Abstraction for creating HttpClients. Allows SSL configuration.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HttpClientBuilder {
+    public static enum HostnameVerificationPolicy {
+        /**
+         * Hostname verification is not done on the server's certificate
+         */
+        ANY,
+        /**
+         * Allows wildcards in subdomain names i.e. *.foo.com
+         */
+        WILDCARD,
+        /**
+         * CN must match hostname connecting to
+         */
+        STRICT
+    }
+
+
+    /**
+     * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+     * @version $Revision: 1 $
+     */
+    private static class PassthroughTrustManager implements X509TrustManager {
+        public void checkClientTrusted(X509Certificate[] chain,
+                                       String authType) throws CertificateException {
+        }
+
+        public void checkServerTrusted(X509Certificate[] chain,
+                                       String authType) throws CertificateException {
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            return null;
+        }
+    }
+
+    protected KeyStore truststore;
+    protected KeyStore clientKeyStore;
+    protected String clientPrivateKeyPassword;
+    protected boolean disableTrustManager;
+    protected HostnameVerificationPolicy policy = HostnameVerificationPolicy.WILDCARD;
+    protected SSLContext sslContext;
+    protected int connectionPoolSize = 100;
+    protected int maxPooledPerRoute = 0;
+    protected long connectionTTL = -1;
+    protected TimeUnit connectionTTLUnit = TimeUnit.MILLISECONDS;
+    protected HostnameVerifier verifier = null;
+    protected long socketTimeout = -1;
+    protected TimeUnit socketTimeoutUnits = TimeUnit.MILLISECONDS;
+    protected long establishConnectionTimeout = -1;
+    protected TimeUnit establishConnectionTimeoutUnits = TimeUnit.MILLISECONDS;
+
+
+    /**
+     * Socket inactivity timeout
+     *
+     * @param timeout
+     * @param unit
+     * @return
+     */
+    public HttpClientBuilder socketTimeout(long timeout, TimeUnit unit)
+    {
+        this.socketTimeout = timeout;
+        this.socketTimeoutUnits = unit;
+        return this;
+    }
+
+    /**
+     * When trying to make an initial socket connection, what is the timeout?
+     *
+     * @param timeout
+     * @param unit
+     * @return
+     */
+    public HttpClientBuilder establishConnectionTimeout(long timeout, TimeUnit unit)
+    {
+        this.establishConnectionTimeout = timeout;
+        this.establishConnectionTimeoutUnits = unit;
+        return this;
+    }
+
+    public HttpClientBuilder connectionTTL(long ttl, TimeUnit unit) {
+        this.connectionTTL = ttl;
+        this.connectionTTLUnit = unit;
+        return this;
+    }
+
+    public HttpClientBuilder maxPooledPerRoute(int maxPooledPerRoute) {
+        this.maxPooledPerRoute = maxPooledPerRoute;
+        return this;
+    }
+
+    public HttpClientBuilder connectionPoolSize(int connectionPoolSize) {
+        this.connectionPoolSize = connectionPoolSize;
+        return this;
+    }
+
+    /**
+     * Disable trust management and hostname verification. <i>NOTE</i> this is a security
+     * hole, so only set this option if you cannot or do not want to verify the identity of the
+     * host you are communicating with.
+     */
+    public HttpClientBuilder disableTrustManager() {
+        this.disableTrustManager = true;
+        return this;
+    }
+
+    /**
+     * SSL policy used to verify hostnames
+     *
+     * @param policy
+     * @return
+     */
+    public HttpClientBuilder hostnameVerification(HostnameVerificationPolicy policy) {
+        this.policy = policy;
+        return this;
+    }
+
+
+    public HttpClientBuilder sslContext(SSLContext sslContext) {
+        this.sslContext = sslContext;
+        return this;
+    }
+
+    public HttpClientBuilder trustStore(KeyStore truststore) {
+        this.truststore = truststore;
+        return this;
+    }
+
+    public HttpClientBuilder keyStore(KeyStore keyStore, String password) {
+        this.clientKeyStore = keyStore;
+        this.clientPrivateKeyPassword = password;
+        return this;
+    }
+
+    public HttpClientBuilder keyStore(KeyStore keyStore, char[] password) {
+        this.clientKeyStore = keyStore;
+        this.clientPrivateKeyPassword = new String(password);
+        return this;
+    }
+
+
+    static class VerifierWrapper implements X509HostnameVerifier {
+        protected HostnameVerifier verifier;
+
+        VerifierWrapper(HostnameVerifier verifier) {
+            this.verifier = verifier;
+        }
+
+        @Override
+        public void verify(String host, SSLSocket ssl) throws IOException {
+            if (!verifier.verify(host, ssl.getSession())) throw new SSLException("Hostname verification failure");
+        }
+
+        @Override
+        public void verify(String host, X509Certificate cert) throws SSLException {
+            throw new SSLException("This verification path not implemented");
+        }
+
+        @Override
+        public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
+            throw new SSLException("This verification path not implemented");
+        }
+
+        @Override
+        public boolean verify(String s, SSLSession sslSession) {
+            return verifier.verify(s, sslSession);
+        }
+    }
+
+    public HttpClient build() {
+        X509HostnameVerifier verifier = null;
+        if (this.verifier != null) verifier = new VerifierWrapper(this.verifier);
+        else {
+            switch (policy) {
+                case ANY:
+                    verifier = new AllowAllHostnameVerifier();
+                    break;
+                case WILDCARD:
+                    verifier = new BrowserCompatHostnameVerifier();
+                    break;
+                case STRICT:
+                    verifier = new StrictHostnameVerifier();
+                    break;
+            }
+        }
+        try {
+            SSLSocketFactory sslsf = null;
+            SSLContext theContext = sslContext;
+            if (disableTrustManager) {
+                theContext = SSLContext.getInstance("SSL");
+                theContext.init(null, new TrustManager[]{new PassthroughTrustManager()},
+                        new SecureRandom());
+                verifier = new AllowAllHostnameVerifier();
+                sslsf = new SSLSocketFactory(theContext, verifier);
+            } else if (theContext != null) {
+                sslsf = new SSLSocketFactory(theContext, verifier);
+            } else if (clientKeyStore != null || truststore != null) {
+                sslsf = new SSLSocketFactory(SSLSocketFactory.TLS, clientKeyStore, clientPrivateKeyPassword, truststore, null, verifier);
+            } else {
+                final SSLContext tlsContext = SSLContext.getInstance(SSLSocketFactory.TLS);
+                tlsContext.init(null, null, null);
+                sslsf = new SSLSocketFactory(tlsContext, verifier);
+            }
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(
+                    new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
+            Scheme httpsScheme = new Scheme("https", 443, sslsf);
+            registry.register(httpsScheme);
+            ClientConnectionManager cm = null;
+            if (connectionPoolSize > 0) {
+                ThreadSafeClientConnManager tcm = new ThreadSafeClientConnManager(registry, connectionTTL, connectionTTLUnit);
+                tcm.setMaxTotal(connectionPoolSize);
+                if (maxPooledPerRoute == 0) maxPooledPerRoute = connectionPoolSize;
+                tcm.setDefaultMaxPerRoute(maxPooledPerRoute);
+                cm = tcm;
+
+            } else {
+                cm = new SingleClientConnManager(registry);
+            }
+            BasicHttpParams params = new BasicHttpParams();
+            if (socketTimeout > -1)
+            {
+                HttpConnectionParams.setSoTimeout(params, (int) socketTimeoutUnits.toMillis(socketTimeout));
+
+            }
+            if (establishConnectionTimeout > -1)
+            {
+                HttpConnectionParams.setConnectionTimeout(params, (int)establishConnectionTimeoutUnits.toMillis(establishConnectionTimeout));
+            }
+            return new DefaultHttpClient(cm, params);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java
new file mode 100755
index 0000000..469ab06
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java
@@ -0,0 +1,140 @@
+package org.keycloak.adapters;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.message.BasicNameValuePair;
+import org.keycloak.adapters.config.RealmConfiguration;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.KeycloakUriBuilder;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class TokenGrantRequest {
+
+    public static class HttpFailure extends Exception {
+        private int status;
+        private String error;
+
+        public HttpFailure(int status, String error) {
+            this.status = status;
+            this.error = error;
+        }
+
+        public int getStatus() {
+            return status;
+        }
+
+        public String getError() {
+            return error;
+        }
+    }
+
+    public static AccessTokenResponse invoke(RealmConfiguration config, String code, String redirectUri) throws HttpFailure, IOException {
+        String codeUrl = config.getCodeUrl();
+        String client_id = config.getMetadata().getResourceName();
+        Map<String,String> credentials = config.getResourceCredentials();
+        HttpClient client = config.getClient();
+
+        return invoke(client, code, codeUrl, redirectUri, client_id, credentials);
+    }
+
+    public static AccessTokenResponse invoke(HttpClient client, String code, String codeUrl, String redirectUri, String client_id, Map<String, String> credentials) throws IOException, HttpFailure {
+        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+        redirectUri = stripOauthParametersFromRedirect(redirectUri);
+        String password = credentials.get("password");
+        formparams.add(new BasicNameValuePair("grant_type", "authorization_code"));
+        formparams.add(new BasicNameValuePair("code", code));
+        formparams.add(new BasicNameValuePair("client_id", client_id));
+        formparams.add(new BasicNameValuePair(CredentialRepresentation.PASSWORD, password));
+        formparams.add(new BasicNameValuePair("redirect_uri", redirectUri));
+        HttpResponse response = null;
+        UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
+        HttpPost post = new HttpPost(codeUrl);
+        post.setEntity(form);
+        response = client.execute(post);
+        int status = response.getStatusLine().getStatusCode();
+        HttpEntity entity = response.getEntity();
+        if (status != 200) {
+            error(status, entity);
+        }
+        if (entity == null) {
+            throw new HttpFailure(status, null);
+        }
+        InputStream is = entity.getContent();
+        try {
+            return JsonSerialization.readValue(is, AccessTokenResponse.class);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ignored) {
+
+            }
+        }
+    }
+
+
+    protected static String readString(InputStream in) throws IOException
+    {
+        char[] buffer = new char[1024];
+        StringBuilder builder = new StringBuilder();
+        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+        int wasRead = 0;
+        do
+        {
+            wasRead = reader.read(buffer, 0, 1024);
+            if (wasRead > 0)
+            {
+                builder.append(buffer, 0, wasRead);
+            }
+        }
+        while (wasRead > -1);
+
+        return builder.toString();
+    }
+
+
+    protected static void error(int status, HttpEntity entity) throws HttpFailure, IOException {
+       String body = null;
+        if (entity != null) {
+            InputStream is = entity.getContent();
+            try {
+                body = readString(is);
+            } catch (IOException e) {
+
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException ignored) {
+
+                }
+            }
+        }
+        throw new HttpFailure(status, body);
+    }
+
+    protected static String stripOauthParametersFromRedirect(String uri) {
+        KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
+                .replaceQueryParam("code", null)
+                .replaceQueryParam("state", null);
+        return builder.build().toString();
+    }
+
+
+
+}
diff --git a/integration/as7-eap6/adapter/pom.xml b/integration/as7-eap6/adapter/pom.xml
index 3950f6b..34a0ef9 100755
--- a/integration/as7-eap6/adapter/pom.xml
+++ b/integration/as7-eap6/adapter/pom.xml
@@ -23,30 +23,38 @@
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-adapter-core</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.spec.javax.servlet</groupId>
-            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
-            <scope>provided</scope>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.1.2</version>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-jaxrs</artifactId>
-            <scope>provided</scope>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-xc</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
             <scope>provided</scope>
         </dependency>
-
         <dependency>
             <groupId>org.jboss.web</groupId>
             <artifactId>jbossweb</artifactId>
@@ -60,12 +68,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.picketbox</groupId>
-            <artifactId>picketbox</artifactId>
-            <version>4.0.7.Final</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
index 25f85db..5738b3d 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
@@ -18,9 +18,9 @@ import java.util.Set;
 
 /**
  * Pre-installed actions that must be authenticated
- *
+ * <p/>
  * Actions include:
- *
+ * <p/>
  * CORS Origin Check and Response headers
  * K_QUERY_BEARER_TOKEN: Get bearer token from server for Javascripts CORS requests
  *
@@ -47,24 +47,24 @@ public class AuthenticatedActionsValve extends ValveBase {
         if (corsRequest(request, response, session)) return;
         String requestUri = request.getRequestURI();
         if (requestUri.endsWith("K_QUERY_BEARER_TOKEN")) {
-           queryBearerToken(request, response, session);
-           return;
+            queryBearerToken(request, response, session);
+            return;
         }
         getNext().invoke(request, response);
     }
 
     public SkeletonKeySession getSkeletonKeySession(Request request) {
-        SkeletonKeySession skSession = (SkeletonKeySession)request.getAttribute(SkeletonKeySession.class.getName());
+        SkeletonKeySession skSession = (SkeletonKeySession) request.getAttribute(SkeletonKeySession.class.getName());
         if (skSession != null) return skSession;
         Session session = request.getSessionInternal();
         if (session != null) {
-           return (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
+            return (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
         }
         return null;
     }
 
     protected void queryBearerToken(Request request, Response response, SkeletonKeySession session) throws IOException, ServletException {
-        log.debugv("queryBearerToken {0}",request.getRequestURI());
+        log.debugv("queryBearerToken {0}", request.getRequestURI());
         if (abortTokenResponse(request, response, session)) return;
         response.setStatus(200);
         response.setContentType("text/plain");
@@ -75,7 +75,7 @@ public class AuthenticatedActionsValve extends ValveBase {
 
     protected boolean abortTokenResponse(Request request, Response response, SkeletonKeySession session) throws IOException {
         if (session == null) {
-            log.debugv("session was null, sending back 401: {0}",request.getRequestURI());
+            log.debugv("session was null, sending back 401: {0}", request.getRequestURI());
             response.sendError(401);
             return true;
         }
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
index 95f7b53..2f5e379 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
@@ -10,8 +10,8 @@ import org.apache.catalina.connector.Response;
 import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.deploy.LoginConfig;
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeySession;
 import org.keycloak.adapters.as7.config.CatalinaAdapterConfigLoader;
 import org.keycloak.adapters.config.AdapterConfig;
 import org.keycloak.adapters.config.AdapterConfigLoader;
@@ -63,7 +63,7 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements 
             }
             super.invoke(request, response);
         } finally {
-            ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+            SkeletonKeySession.clearContext();
         }
     }
 
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
index 3d8bd0d..5745444 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
@@ -2,7 +2,6 @@ package org.keycloak.adapters.as7;
 
 import org.apache.catalina.connector.Request;
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.ResourceMetadata;
 import org.keycloak.SkeletonKeyPrincipal;
@@ -109,7 +108,7 @@ public class CatalinaBearerTokenAuthenticator {
         request.setAuthType("OAUTH_BEARER");
         SkeletonKeySession skSession = new SkeletonKeySession(tokenString, token, resourceMetadata);
         request.setAttribute(SkeletonKeySession.class.getName(), skSession);
-        ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+        SkeletonKeySession.pushContext(skSession);
 
         return true;
     }
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/CatalinaAdapterConfigLoader.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/CatalinaAdapterConfigLoader.java
index 64c509a..604a2ed 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/CatalinaAdapterConfigLoader.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/CatalinaAdapterConfigLoader.java
@@ -1,13 +1,13 @@
 package org.keycloak.adapters.as7.config;
 
 import org.apache.catalina.Context;
+import org.keycloak.adapters.config.RealmConfigurationLoader;
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 
-public class CatalinaAdapterConfigLoader extends RealmConfigurationLoader
-{
+public class CatalinaAdapterConfigLoader extends RealmConfigurationLoader {
 
     public CatalinaAdapterConfigLoader(Context context) {
         InputStream is = null;
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
index 75648b1..8d21b67 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
@@ -2,19 +2,16 @@ package org.keycloak.adapters.as7;
 
 import org.jboss.logging.Logger;
 import org.keycloak.RSATokenVerifier;
-import org.keycloak.adapters.RealmConfiguration;
 import org.keycloak.VerificationException;
+import org.keycloak.adapters.TokenGrantRequest;
+import org.keycloak.adapters.config.RealmConfiguration;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.SkeletonKeyToken;
-import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.util.KeycloakUriBuilder;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Form;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
 import java.io.IOException;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicLong;
@@ -137,7 +134,7 @@ public class ServletOAuthLogin {
                 // disabled?
                 return null;
             }
-            UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1);
+            KeycloakUriBuilder secureUrl = KeycloakUriBuilder.fromUri(url).scheme("https").port(-1);
             if (port != 443) secureUrl.port(port);
             url = secureUrl.build().toString();
         }
@@ -159,7 +156,7 @@ public class ServletOAuthLogin {
         String state = getStateCode();
         String redirect = getRedirectUri(state);
         if (redirect == null) {
-            sendError(Response.Status.FORBIDDEN.getStatusCode());
+            sendError(HttpServletResponse.SC_FORBIDDEN);
             return;
         }
         setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired());
@@ -216,42 +213,28 @@ public class ServletOAuthLogin {
         // abort if not HTTPS
         if (realmInfo.isSslRequired() && !isRequestSecure()) {
             log.error("SSL is required");
-            sendError(Response.Status.FORBIDDEN.getStatusCode());
+            sendError(HttpServletResponse.SC_FORBIDDEN);
             return false;
         }
 
         if (!checkStateCookie()) return false;
 
-        String client_id = realmInfo.getMetadata().getResourceName();
-        String password = realmInfo.getResourceCredentials().asMap().getFirst("password");
-        //String authHeader = BasicAuthHelper.createHeader(client_id, password);
         String redirectUri = stripOauthParametersFromRedirect();
-        Form form = new Form();
-        form.param("grant_type", "authorization_code")
-                .param("code", code)
-                .param("client_id", client_id)
-                .param(CredentialRepresentation.PASSWORD, password)
-                .param("redirect_uri", redirectUri);
-
-        Response res = realmInfo.getCodeUrl().request()
-                //.header(HttpHeaders.AUTHORIZATION, authHeader)
-                .post(Entity.form(form));
-        AccessTokenResponse tokenResponse;
+        AccessTokenResponse tokenResponse = null;
         try {
-            if (res.getStatus() != 200) {
-                log.error("failed to turn code into token");
-                log.error("status from server: " + res.getStatus());
-                if (res.getStatus() == 400 && res.getMediaType() != null) {
-                    log.error("   " + res.readEntity(String.class));
-                }
-                sendError(Response.Status.FORBIDDEN.getStatusCode());
-                return false;
+            tokenResponse = TokenGrantRequest.invoke(realmInfo, code, redirectUri);
+        } catch (TokenGrantRequest.HttpFailure failure) {
+            log.error("failed to turn code into token");
+            log.error("status from server: " + failure.getStatus());
+            if (failure.getStatus() == 400 && failure.getError() != null) {
+                log.error("   " + failure.getError());
             }
-            log.debug("media type: " + res.getMediaType());
-            log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
-            tokenResponse = res.readEntity(AccessTokenResponse.class);
-        } finally {
-            res.close();
+            sendError(HttpServletResponse.SC_FORBIDDEN);
+            return false;
+
+        } catch (IOException e) {
+            log.error("failed to turn code into token");
+            sendError(HttpServletResponse.SC_FORBIDDEN);
         }
 
         tokenString = tokenResponse.getToken();
@@ -260,7 +243,7 @@ public class ServletOAuthLogin {
             log.debug("Token Verification succeeded!");
         } catch (VerificationException e) {
             log.error("failed verification of token");
-            sendError(Response.Status.FORBIDDEN.getStatusCode());
+            sendError(HttpServletResponse.SC_FORBIDDEN);
             return false;
         }
         // redirect to URL without oauth query parameters
@@ -273,7 +256,7 @@ public class ServletOAuthLogin {
      */
     protected String stripOauthParametersFromRedirect() {
         StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString());
-        UriBuilder builder = UriBuilder.fromUri(buf.toString())
+        KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(buf.toString())
                 .replaceQueryParam("code", null)
                 .replaceQueryParam("state", null);
         return builder.build().toString();
diff --git a/integration/jaxrs-oauth-client/pom.xml b/integration/jaxrs-oauth-client/pom.xml
new file mode 100755
index 0000000..65282b5
--- /dev/null
+++ b/integration/jaxrs-oauth-client/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<project>
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-alpha-1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-jaxrs-oauth-client</artifactId>
+    <name>Keycloak JAX-RS OAuth Client</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-client</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jackson-provider</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/integration/pom.xml b/integration/pom.xml
index 2100379..5512c45 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -16,6 +16,8 @@
 
     <modules>
         <module>adapter-core</module>
+        <module>jaxrs-oauth-client</module>
+        <module>servlet-oauth-client</module>
         <module>as7-eap6/adapter</module>
         <module>undertow</module>
         <!-- <module>as7-eap6/jboss-modules</module> -->
diff --git a/integration/servlet-oauth-client/pom.xml b/integration/servlet-oauth-client/pom.xml
new file mode 100755
index 0000000..038f1ab
--- /dev/null
+++ b/integration/servlet-oauth-client/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<project>
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-alpha-1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-servlet-oauth-client</artifactId>
+    <name>Keycloak Servlet OAuth Client</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-adapter-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/integration/undertow/pom.xml b/integration/undertow/pom.xml
index 3060d39..f3ae801 100755
--- a/integration/undertow/pom.xml
+++ b/integration/undertow/pom.xml
@@ -23,27 +23,36 @@
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-core</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-adapter-core</artifactId>
             <version>${project.version}</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.jboss.spec.javax.servlet</groupId>
-            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
-            <scope>provided</scope>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.1.2</version>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-jaxrs</artifactId>
-            <scope>provided</scope>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.jboss.resteasy</groupId>
-            <artifactId>resteasy-client</artifactId>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-xc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
             <scope>provided</scope>
         </dependency>
 
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
index ef7120e..749c6b0 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
@@ -6,7 +6,7 @@ import io.undertow.security.idm.Account;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.util.AttachmentKey;
 import org.jboss.logging.Logger;
-import org.keycloak.adapters.RealmConfiguration;
+import org.keycloak.adapters.config.RealmConfiguration;
 import org.keycloak.ResourceMetadata;
 import org.keycloak.SkeletonKeyPrincipal;
 import org.keycloak.SkeletonKeySession;
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
index 16f71bd..02a39d4 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
@@ -8,6 +8,7 @@ import io.undertow.servlet.api.DeploymentInfo;
 import io.undertow.servlet.api.ServletSessionConfig;
 import org.jboss.logging.Logger;
 import org.keycloak.adapters.config.AdapterConfig;
+import org.keycloak.adapters.config.RealmConfigurationLoader;
 
 import javax.servlet.ServletContext;
 import java.io.InputStream;
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java
index 8806ac6..433feb2 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java
@@ -8,16 +8,14 @@ import io.undertow.server.handlers.CookieImpl;
 import io.undertow.util.Headers;
 import org.jboss.logging.Logger;
 import org.keycloak.RSATokenVerifier;
-import org.keycloak.adapters.RealmConfiguration;
+import org.keycloak.adapters.config.RealmConfiguration;
 import org.keycloak.VerificationException;
+import org.keycloak.adapters.TokenGrantRequest;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.SkeletonKeyToken;
-import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.util.KeycloakUriBuilder;
 
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Form;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
 import java.util.Deque;
 import java.util.Map;
 import java.util.UUID;
@@ -60,7 +58,7 @@ public class OAuthAuthenticator {
     }
 
     protected String getRequestUrl() {
-        UriBuilder uriBuilder = UriBuilder.fromUri(exchange.getRequestURI())
+        KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(exchange.getRequestURI())
                 .replaceQuery(exchange.getQueryString());
         if (!exchange.isHostIncludedInRequestURI()) uriBuilder.scheme(exchange.getRequestScheme()).host(exchange.getHostAndPort());
         return uriBuilder.build().toString();
@@ -107,7 +105,7 @@ public class OAuthAuthenticator {
                 // disabled?
                 return null;
             }
-            UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1);
+            KeycloakUriBuilder secureUrl = KeycloakUriBuilder.fromUri(url).scheme("https").port(-1);
             if (port != 443) secureUrl.port(port);
             url = secureUrl.build().toString();
         }
@@ -237,34 +235,20 @@ public class OAuthAuthenticator {
         KeycloakChallenge challenge = checkStateCookie();
         if (challenge != null) return challenge;
 
-        String client_id = realmInfo.getMetadata().getResourceName();
-        String password = realmInfo.getResourceCredentials().asMap().getFirst("password");
-        //String authHeader = BasicAuthHelper.createHeader(client_id, password);
-        redirectUri = stripOauthParametersFromRedirect();
-        Form form = new Form();
-        form.param("grant_type", "authorization_code")
-                .param("code", code)
-                .param("client_id", client_id)
-                .param(CredentialRepresentation.PASSWORD, password)
-                .param("redirect_uri", redirectUri);
-
-        Response res = realmInfo.getCodeUrl().request()
-                .post(Entity.form(form));
-        AccessTokenResponse tokenResponse;
+        AccessTokenResponse tokenResponse = null;
         try {
-            if (res.getStatus() != 200) {
-                log.error("failed to turn code into token");
-                log.error("status from server: " + res.getStatus());
-                if (res.getStatus() == 400 && res.getMediaType() != null) {
-                    log.error("   " + res.readEntity(String.class));
-                }
-                return challenge(403);
+            tokenResponse = TokenGrantRequest.invoke(realmInfo, code, redirectUri);
+        } catch (TokenGrantRequest.HttpFailure failure) {
+            log.error("failed to turn code into token");
+            log.error("status from server: " + failure.getStatus());
+            if (failure.getStatus() == 400 && failure.getError() != null) {
+                log.error("   " + failure.getError());
             }
-            log.debug("media type: " + res.getMediaType());
-            log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
-            tokenResponse = res.readEntity(AccessTokenResponse.class);
-        } finally {
-            res.close();
+            return challenge(403);
+
+        } catch (IOException e) {
+            log.error("failed to turn code into token");
+            return challenge(403);
         }
 
         tokenString = tokenResponse.getToken();
@@ -283,7 +267,7 @@ public class OAuthAuthenticator {
      * strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits
      */
     protected String stripOauthParametersFromRedirect() {
-        UriBuilder builder = UriBuilder.fromUri(exchange.getRequestURI())
+        KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(exchange.getRequestURI())
                 .replaceQuery(exchange.getQueryString())
                 .replaceQueryParam("code", null)
                 .replaceQueryParam("state", null);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
index 5c33717..9df6863 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
@@ -3,7 +3,7 @@ package org.keycloak.adapters.undertow;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.servlet.api.ConfidentialPortManager;
 import io.undertow.servlet.handlers.ServletRequestContext;
-import org.keycloak.adapters.RealmConfiguration;
+import org.keycloak.adapters.config.RealmConfiguration;
 import org.keycloak.ResourceMetadata;
 import org.keycloak.SkeletonKeySession;
 import org.keycloak.adapters.config.AdapterConfig;
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletOAuthAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletOAuthAuthenticator.java
index ce807a6..e891a1d 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletOAuthAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletOAuthAuthenticator.java
@@ -2,7 +2,7 @@ package org.keycloak.adapters.undertow;
 
 import io.undertow.server.HttpServerExchange;
 import io.undertow.servlet.api.ConfidentialPortManager;
-import org.keycloak.adapters.RealmConfiguration;
+import org.keycloak.adapters.config.RealmConfiguration;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

pom.xml 11(+9 -2)

diff --git a/pom.xml b/pom.xml
index fc62fe8..0921449 100755
--- a/pom.xml
+++ b/pom.xml
@@ -76,8 +76,8 @@
         <module>core</module>
         <module>core-jaxrs</module>
         <module>model</module>
-        <module>services</module>
         <module>integration</module>
+        <module>services</module>
         <module>social</module>
         <module>forms</module>
         <module>admin-ui-styles</module>
@@ -327,7 +327,14 @@
                 <artifactId>mysql-connector-java</artifactId>
                 <version>${mysql.version}</version>
             </dependency>
-
+            <!-- Keep this at 4.1.2 to make sure we're compatible with AS7 -->
+            <!-- the dependency seems to override Resteasy 3.0.5's dependeing on 4.2.1
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>4.1.2</version>
+            </dependency>
+             -->
         </dependencies>
     </dependencyManagement>
 

services/pom.xml 16(+11 -5)

diff --git a/services/pom.xml b/services/pom.xml
index 56e8481..3c1e0fb 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -37,6 +37,12 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-jaxrs-oauth-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-jpa</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
@@ -83,7 +89,7 @@
                 </exclusion>
             </exclusions>
         </dependency>
-         <dependency>
+        <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>jaxrs-api</artifactId>
             <scope>provided</scope>
@@ -162,11 +168,11 @@
             <artifactId>hibernate-entitymanager</artifactId>
             <scope>test</scope>
         </dependency>
-		<dependency>
-    		<groupId>com.icegreen</groupId>
-    		<artifactId>greenmail</artifactId>
+        <dependency>
+            <groupId>com.icegreen</groupId>
+            <artifactId>greenmail</artifactId>
             <scope>test</scope>
-		</dependency>        
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
index f6cc0d0..f6a4911 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocialServlet.java
@@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.URI;
 import java.nio.charset.Charset;
 import java.util.List;
 
@@ -34,7 +35,13 @@ public class DummySocialServlet extends HttpServlet {
         String state = null;
         String redirectUri = null;
 
-        List<NameValuePair> query = URLEncodedUtils.parse(req.getQueryString(), Charset.forName("UTF-8"));
+        List<NameValuePair> query = null;
+        try {
+            URI uri = URI.create(req.getRequestURL().append('?').append(req.getQueryString()).toString());
+            query = URLEncodedUtils.parse(uri, "UTF-8");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
         for (NameValuePair p : query) {
             if ("state".equals(p.getName())) {
                 state = p.getValue();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index 6b6e1d5..49acb71 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -43,6 +43,7 @@ import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 
 import javax.ws.rs.core.UriBuilder;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.Charset;
@@ -127,7 +128,12 @@ public class OAuthClient {
             parameters.add(new BasicNameValuePair("password", password));
         }
 
-        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charset.forName("UTF-8"));
+        UrlEncodedFormEntity formEntity = null;
+        try {
+            formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
         post.setEntity(formEntity);
 
         try {