Skip to content

Instantly share code, notes, and snippets.

@shimondoodkin
Last active January 19, 2021 01:52
Show Gist options
  • Select an option

  • Save shimondoodkin/647c3fdcea34c22ff5e0e338c13636b0 to your computer and use it in GitHub Desktop.

Select an option

Save shimondoodkin/647c3fdcea34c22ff5e0e338c13636b0 to your computer and use it in GitHub Desktop.

Revisions

  1. shimondoodkin revised this gist Jan 19, 2021. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions OpenIdRawRequestToken.java
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,7 @@

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    @@ -78,12 +79,15 @@ private static String HttpPOST_Form_AcceptsJSON_CheckHTTPS(String uri,HashMap<St

    private static String HttpURLConnection_GetResponseBody(HttpURLConnection connection) throws IOException, NullPointerException
    {
    BufferedReader br = null;
    if (100 <= connection.getResponseCode() && connection.getResponseCode() <= 399) {
    br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    return convertInputStreamToString(connection.getInputStream());
    } else {
    br = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
    return convertInputStreamToString(connection.getErrorStream());
    }
    }

    private static String convertInputStreamToString(InputStream is) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(is));;
    StringBuilder sb=new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
    @@ -280,7 +284,6 @@ public static Token get_OpenId_Berer_Token_cached(String OpenId_DiscoveryEndpoin
    }



    public static void main(String[] args) {

    //example:
  2. shimondoodkin created this gist Jan 19, 2021.
    317 changes: 317 additions & 0 deletions OpenIdRawRequestToken.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,317 @@
    package open_id_raw_request_token;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.StringJoiner;

    import org.json.simple.JSONObject;
    import org.json.simple.JSONValue;


    public class OpenIdRawRequestToken {




    private static String HttpGET_AcceptsJSON_CheckHTTPS(String uri ) throws MalformedURLException, Exception, IOException, NullPointerException {
    URL url = new URL(uri);
    if(!url.getProtocol().equals("https"))
    throw new Exception("OpenIdRawRequestToken - not https "+uri);

    HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // Open a connection(?) on the URL(??) and cast the response(???)
    connection.setRequestProperty("accept", "application/json"); // Now it's "open", we can set the request method, headers etc.

    String strjson=HttpURLConnection_GetResponseBody(connection);
    return strjson;
    }

    private static String queryString(HashMap<String, String> PostFormValues) throws UnsupportedEncodingException {
    StringJoiner sj = new StringJoiner("&");
    for(Map.Entry<String,String> entry : PostFormValues.entrySet())
    sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "="
    + URLEncoder.encode(entry.getValue(), "UTF-8"));
    String qs=sj.toString();
    return qs;
    }

    private static String HttpPOST_String_AcceptsJSON_CheckHTTPS(String uri,String PostData,String PostContentType) throws MalformedURLException, Exception, IOException, NullPointerException {
    URL url = new URL(uri);
    if(!url.getProtocol().equals("https"))
    throw new Exception("OpenIdRawRequestToken - not https "+uri);

    HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // Open a connection(?) on the URL(??) and cast the response(???)
    connection.setRequestProperty("accept", "application/json"); // Now it's "open", we can set the request method, headers etc.
    connection.setRequestMethod("POST"); // PUT is another valid option
    connection.setDoOutput(true);

    byte[] out = PostData.getBytes(StandardCharsets.UTF_8);
    int length = out.length;

    connection.setFixedLengthStreamingMode(length);
    connection.setRequestProperty("Content-Type", PostContentType);
    connection.connect();
    OutputStream os = connection.getOutputStream();
    os.write(out);


    String strjson=HttpURLConnection_GetResponseBody(connection);
    return strjson;
    }


    private static String HttpPOST_Form_AcceptsJSON_CheckHTTPS(String uri,HashMap<String, String> PostFormValues) throws MalformedURLException, Exception, IOException,NullPointerException {
    return HttpPOST_String_AcceptsJSON_CheckHTTPS( uri,queryString(PostFormValues),"application/x-www-form-urlencoded; charset=UTF-8");
    }

    private static String HttpURLConnection_GetResponseBody(HttpURLConnection connection) throws IOException, NullPointerException
    {
    BufferedReader br = null;
    if (100 <= connection.getResponseCode() && connection.getResponseCode() <= 399) {
    br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    } else {
    br = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
    }
    StringBuilder sb=new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
    sb.append(line);
    }
    return sb.toString();
    }

    public static Token get_OpenId_Berer_Token(String OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash, String scope, String client_id, String client_secret )
    throws Exception
    {
    try {

    JSONObject DiscoveryEndpoint_JSON = get_OpenId_Discovery(OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash);

    String url_token_endpoint=(String) DiscoveryEndpoint_JSON.get("token_endpoint");

    return openId_Request_BererToken(url_token_endpoint, scope, client_id, client_secret );

    } catch (MalformedURLException e) {
    //e.printStackTrace();
    throw new Exception("get_OpoenId_Berer_Token - MalformedURLException",e);
    } catch (IOException e) {
    //e.printStackTrace();
    throw new Exception("get_OpoenId_Berer_Token - IOException",e);
    }
    }

    private static Token openId_Request_BererToken(String url_token_endpoint, String scope, String client_id, String client_secret )
    throws MalformedURLException, Exception, IOException, NullPointerException {
    HashMap<String, String> PostValues=new HashMap<String, String>();
    PostValues.put("grant_type", "client_credentials");

    PostValues.put("scope", scope);
    PostValues.put("client_id", client_id);
    PostValues.put("client_secret", client_secret);

    final JSONObject TokenEndpoint_JSON=(JSONObject) JSONValue.parse(HttpPOST_Form_AcceptsJSON_CheckHTTPS(url_token_endpoint,PostValues));

    @SuppressWarnings("unchecked")
    String error=(String) TokenEndpoint_JSON.getOrDefault("error", "");

    if(!error.isEmpty())
    throw new Error("OpenIdRawRequestToken - token request error "+error);

    Token token =new Token();

    token.access_token=(String)TokenEndpoint_JSON.get("access_token");
    token.expires_in=((Long)TokenEndpoint_JSON.get("expires_in")).intValue();
    token.token_type=(String)TokenEndpoint_JSON.get("token_type");
    token.scope=(String)TokenEndpoint_JSON.get("scope");
    token.date=System.currentTimeMillis();
    token.dateExpiers=(System.currentTimeMillis()+(token.expires_in*1000))-60000;
    return token;
    }

    public static class Token {
    public long dateExpiers;
    public long date;
    public String access_token;
    public int expires_in;
    public String token_type;
    public String scope;
    boolean failed=false;
    public boolean isExpierd() {
    return System.currentTimeMillis()>dateExpiers;
    }
    public boolean isFailed() {
    return failed;
    }
    public void Failed() {
    failed=true;
    }

    }


    private static JSONObject get_OpenId_Discovery(String OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash)
    throws MalformedURLException, Exception, IOException, NullPointerException {
    JSONObject DiscoveryEndpoint_JSON;

    final String DiscoveryEndpoint_Authority = OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash ;


    String openid_default_discovery_endpoint_suffix = "/.well-known/openid-configuration";
    String DiscoveryEndpoint_Url = DiscoveryEndpoint_Authority + openid_default_discovery_endpoint_suffix ;

    DiscoveryEndpoint_JSON = (JSONObject) JSONValue.parse(HttpGET_AcceptsJSON_CheckHTTPS(DiscoveryEndpoint_Url));

    OpenId_Discovery_doSomeValidations(DiscoveryEndpoint_JSON,DiscoveryEndpoint_Authority);

    return DiscoveryEndpoint_JSON;
    }


    private static void OpenId_Discovery_doSomeValidations(JSONObject DiscoveryEndpoint_JSON,String DiscoveryEndpoint_Authority ) throws Exception, MalformedURLException {
    // do some validations before returning endpoint

    @SuppressWarnings("unchecked")
    String issuer=(String) DiscoveryEndpoint_JSON.getOrDefault("issuer", "" ) ;
    if( !issuer.equals(DiscoveryEndpoint_Authority))
    throw new Exception("get_OpoenId_Berer_Token issuer error "+issuer + " != "+ DiscoveryEndpoint_Authority);

    ValidateEndpoints(DiscoveryEndpoint_JSON,
    asArrayList(new URL(DiscoveryEndpoint_Authority).getAuthority()),
    new ArrayList<String>(),
    false );
    }

    private static ArrayList<String> asArrayList(String ...args){
    ArrayList<String> list=new ArrayList<String>();
    for(final String el : args)
    list.add(el);
    return list;
    }

    private static void ValidateEndpoints(JSONObject json, ArrayList<String> allowedAuthorities, ArrayList<String> EndpointValidationExcludeList, boolean RequireKeySet) throws MalformedURLException ,Exception
    {
    String OidcConstants_Discovery_JwksUri = "jwks_uri";
    String OidcConstants_Discovery_CheckSessionIframe = "check_session_iframe";


    @SuppressWarnings("rawtypes")
    Iterator it = json.entrySet().iterator();
    while (it.hasNext()) {
    @SuppressWarnings("rawtypes")
    Map.Entry pair = (Map.Entry)it.next();

    String key=((String) pair.getKey()).toLowerCase();

    if (key.endsWith("endpoint") ||
    key.equals(OidcConstants_Discovery_JwksUri) ||
    key.equals(OidcConstants_Discovery_CheckSessionIframe))
    {
    String endpoint = (String) pair.getValue();

    // if endpoint is on exclude list, don't validate
    if (EndpointValidationExcludeList.contains(key))
    {
    continue;
    }

    URL uri = new URL(endpoint); // throws if invalid url

    if (!uri.getProtocol().equals("https"))
    {
    throw new Exception("OpenIdRawRequestToken - Malformed endpoint url from discovery: "+key+" not https url "+endpoint);
    }

    boolean isAllowed = false;
    for(String host : allowedAuthorities)
    {
    if (host.equals(uri.getAuthority()))
    {
    isAllowed = true;
    }
    }

    if (!isAllowed)
    {
    throw new Exception("OpenIdRawRequestToken - an Endpoint has a different host than authority: "+key+" not https url "+endpoint);
    }
    }
    }

    if (RequireKeySet)
    {
    @SuppressWarnings("unchecked")
    String JwksUri=(String) json.getOrDefault(OidcConstants_Discovery_JwksUri, "");
    if (JwksUri.isEmpty())
    {
    throw new Exception("OpenIdRawRequestToken - KeySet endpoint is missing");
    }
    }
    }


    public static HashMap<String,Token> TokenCache=new HashMap<String, Token>();
    public static Token get_OpenId_Berer_Token_cached(String OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash, String scope, String client_id, String client_secret )throws Exception
    {
    final String key=OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash;
    if(TokenCache.containsKey(key))
    {
    Token token=TokenCache.get(key);
    if(token.isExpierd()||token.isFailed())
    TokenCache.remove(key);
    else
    return token;
    }

    Token token = get_OpenId_Berer_Token( OpenId_DiscoveryEndpoint_Authority_Url_base_url_without_trailing_slash, scope, client_id, client_secret );
    TokenCache.put(key,token);
    return token;
    }



    public static void main(String[] args) {

    //example:

    Token token=null;
    try {
    token=get_OpenId_Berer_Token_cached(
    "https://identity.server.com",
    "myscope",
    "myid",
    "mysecret"
    );

    System.out.println(token.access_token);


    URL url = new URL("https://api.server.com");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestProperty("Authorization", "Bearer "+token.access_token);
    connection.setRequestProperty("accept", "application/json");

    String strjson=HttpURLConnection_GetResponseBody(connection);

    System.out.println(strjson);


    }catch(Exception e) {
    if(token!=null) token.Failed();
    e.printStackTrace();
    }

    }

    }