diff --git a/README.md b/README.md index 487c06d..c341369 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # JWTs for Java + This is not an officially supported Google product [![CircleCI](https://img.shields.io/circleci/project/github/auth0/java-jwt.svg?style=flat-square)](https://circleci.com/gh/auth0/java-jwt/tree/master) diff --git a/lib/src/main/java/oicclient/exceptions/WebFingerError.java b/lib/src/main/java/oicclient/exceptions/WebFingerError.java new file mode 100644 index 0000000..f8dd902 --- /dev/null +++ b/lib/src/main/java/oicclient/exceptions/WebFingerError.java @@ -0,0 +1,8 @@ +package oicclient.exceptions; + +public class WebFingerError extends Exception{ + + public WebFingerError(String message) { + super(message); + } +} \ No newline at end of file diff --git a/lib/src/main/java/oicclient/tuples/Tuple.java b/lib/src/main/java/oicclient/tuples/Tuple.java new file mode 100644 index 0000000..6d7e66e --- /dev/null +++ b/lib/src/main/java/oicclient/tuples/Tuple.java @@ -0,0 +1,20 @@ +package oicclient.tuples; + +public class Tuple { + + private Object a; + private Object b; + + public Tuple(Object a, Object b) { + this.a = a; + this.b = b; + } + + public Object getA() { + return a; + } + + public Object getB() { + return b; + } +} \ No newline at end of file diff --git a/lib/src/main/java/oicclient/webfinger/URINormalizer.java b/lib/src/main/java/oicclient/webfinger/URINormalizer.java new file mode 100644 index 0000000..7ff90d3 --- /dev/null +++ b/lib/src/main/java/oicclient/webfinger/URINormalizer.java @@ -0,0 +1,48 @@ +package oicclient.webfinger; + +public class URINormalizer { + + private static boolean hasScheme(String path) { + if (path.contains("://")) { + return true; + } else { + String authority = path.replace("/", "#") + .replace("?", "#").split("#")[0]; + + String hostOrPort; + if (authority.contains(":")) { + hostOrPort = authority.split(":", 1)[1]; + if (hostOrPort.matches("^\\d+$")) { + return false; + } + } else { + return false; + } + } + + return true; + } + + private static boolean isAccountSchemeAssumed(String path) { + String[] arr; + if (path.contains("@")) { + arr = path.split("@"); + String host = arr[arr.length - 1]; + return !(host.contains(":") || host.contains("/") || host.contains("?")); + } else { + return false; + } + } + + String normalize(String path) { + if (!hasScheme(path)) { + if (isAccountSchemeAssumed(path)) { + path = "acct:" + path; + } else { + path = "https://" + path; + } + } + + return path.split("#")[0]; + } +} \ No newline at end of file diff --git a/lib/src/main/java/oicclient/webfinger/WebFinger.java b/lib/src/main/java/oicclient/webfinger/WebFinger.java new file mode 100644 index 0000000..0abbf38 --- /dev/null +++ b/lib/src/main/java/oicclient/webfinger/WebFinger.java @@ -0,0 +1,97 @@ +package oicclient.webfinger; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.base.Strings; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import oicclient.exceptions.WebFingerError; +import oicclient.tuples.Tuple; + +public class WebFinger { + public String defaultRelt; + private JRD jrd; + private List> events; + private static final String WF_URL = "https://%s/.well-known/webfinger"; + + public WebFinger(String defaultRelt) { + this.defaultRelt = defaultRelt; + this.jrd = null; + this.events = new ArrayList<>(); + } + + public String query(String resource, List rel) throws URISyntaxException, WebFingerError { + resource = new URINormalizer().normalize(resource); + List queryParamsTuple = new ArrayList<>(Arrays.asList(new Tuple("resource", resource))); + + if (rel == null) { + if (!Strings.isNullOrEmpty(this.defaultRelt)) { + queryParamsTuple.add(new Tuple("rel", this.defaultRelt)); + } + } else { + for (String index : rel) { + queryParamsTuple.add(new Tuple("rel", index)); + } + } + + String host; + if (resource.startsWith("http")) { + URI uri = new URI(resource); + host = uri.getHost(); + int port = uri.getPort(); + if (port != -1) { + host += ":" + port; + } + } else if (resource.startsWith("acct:")) { + String[] arr = resource.split("@"); + host = arr[arr.length - 1]; + arr = host.replace("/", "#").replace("?", "#").split("#"); + host = arr[0]; + } else if (resource.startsWith("device:")) { + String[] arr = resource.split(":"); + host = arr[1]; + } else { + throw new WebFingerError("Unknown schema"); + } + + String queryParams = ""; + for (int i = 0; i < queryParamsTuple.size(); i++) { + queryParams += queryParamsTuple.get(i).getA() + "=" + queryParamsTuple.get(i).getB(); + if (i != queryParamsTuple.size() - 1) { + queryParams += "&"; + } + } + + return String.format(WF_URL, host) + "?" + URLEncoder.encode(queryParams); + } + + public String query(String resource) throws URISyntaxException, WebFingerError { + return query(resource, null); + } + + public Map httpArgs(JRD jrd) throws JsonProcessingException { + if (jrd == null) { + if (this.jrd != null) { + jrd = this.jrd; + } else { + return null; + } + } + + Map hMap = new HashMap() {{ + put("Access-Control-Allow-Origin", "*"); + put("Content-Type", "application/json; charset=UTF-8"); + }}; + + Map headersAndBody = new HashMap<>(); + headersAndBody.put("headers", hMap); + headersAndBody.put("body", jrd.toJSON()); + + return headersAndBody; + } +} \ No newline at end of file