package com.sap.cloud.lm.sl.cf.client.util;

import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.cloudfoundry.client.lib.util.JsonUtil;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;

public class TokenUtil {

    public static final String DUMMY_TOKEN = "DUMMY";
    public static final UUID DUMMY_UUID = new UUID(0, 0);

    // Scopes
    public static final String SCOPE_CC_READ = "cloud_controller.read";
    public static final String SCOPE_CC_WRITE = "cloud_controller.write";
    public static final String SCOPE_CC_ADMIN = "cloud_controller.admin";
    public static final String SCOPE_SCIM_USERIDS = "scim.userids";
    public static final String SCOPE_PASSWORD_WRITE = "password.write";
    public static final String SCOPE_OPENID = "openid";

    @SuppressWarnings("unchecked")
    public static OAuth2AccessToken createToken(String tokenString) {
        Map<String, Object> tokenInfo = getTokenInfo(tokenString);
        List<String> scope = (List<String>) tokenInfo.get("scope");
        Integer exp = (Integer) tokenInfo.get("exp");
        if (scope == null || exp == null) {
            return null;
        }
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(tokenString);
        token.setExpiration(new Date(exp.longValue() * 1000));
        token.setScope(new HashSet<String>(scope));
        token.setAdditionalInformation(tokenInfo);
        return token;
    }

    public static OAuth2AccessToken createDummyToken(String userName, String clientId) {
        List<String> scope = Arrays.asList(SCOPE_CC_READ, SCOPE_CC_WRITE, SCOPE_CC_ADMIN, SCOPE_SCIM_USERIDS, SCOPE_PASSWORD_WRITE,
            SCOPE_OPENID);
        Map<String, Object> tokenInfo = new HashMap<>();
        tokenInfo.put("scope", scope);
        tokenInfo.put("exp", Long.MAX_VALUE / 1000);
        tokenInfo.put("user_name", userName);
        tokenInfo.put("user_id", DUMMY_UUID.toString());
        tokenInfo.put("client_id", clientId);
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(DUMMY_TOKEN);
        token.setExpiration(new Date(Long.MAX_VALUE));
        token.setScope(new HashSet<String>(scope));
        token.setAdditionalInformation(tokenInfo);
        return token;
    }

    private static Map<String, Object> getTokenInfo(String tokenString) {
        String userJson = "{}";
        try {
            int x = tokenString.indexOf('.');
            int y = tokenString.indexOf('.', x + 1);
            String encodedString = tokenString.substring(x + 1, y);
            byte[] decodedBytes = Base64.getDecoder()
                .decode(encodedString);
            userJson = new String(decodedBytes, 0, decodedBytes.length, "UTF-8");
        } catch (IndexOutOfBoundsException e) {
            // Do nothing
        } catch (IOException e) {
            // Do nothing
        }
        return (JsonUtil.convertJsonToMap(userJson));
    }

}

@@ -56,22 +56,36 @@
 ava.
+n
 io.
-IOException
+charset.StandardCharsets
 ;%0D%0Ai
@@ -135,16 +135,81 @@
 ase64;%0D%0A
+import java.util.Collections;%0D%0Aimport java.util.Base64.Decoder;%0D%0A
 import j
@@ -1281,28 +1281,26 @@
 nInfo = 
-get
+parse
 Token
-Info
 (tokenSt
@@ -2675,20 +2675,18 @@
 ct%3E 
-get
+parse
 Token
-Info
 (Str
@@ -2723,59 +2723,21 @@
 ring
- userJson = %22%7B%7D%22;%0D%0A        try %7B%0D%0A            int x
+%5B%5D tokenParts
  = t
@@ -2747,27 +2747,27 @@
 nString.
-indexOf('.'
+split(%22%5C%5C.%22
 );%0D%0A    
@@ -2774,215 +2774,220 @@
     
-    int y = tokenString.indexOf('.', x + 1);%0D%0A            String encodedString = tokenString.substring(x + 1, y);%0D%0A            byte%5B%5D decodedBytes = Base64.getDecoder()%0D%0A                .decode(encodedString
+if (tokenParts.length != 3) %7B%0D%0A            // The token should have three parts (header, body and signature) separated by a dot. It doesn't, so we consider it as invalid.%0D%0A            return Collections.emptyMap(
 );%0D%0A
@@ -2998,189 +2998,161 @@
     
+%7D%0D%0A
     
-userJson = new String(decodedBytes, 0, decodedBytes.length, %22UTF-8%22);%0D%0A        %7D catch (IndexOutOfBoundsException e) %7B%0D%0A            // Do nothing%0D%0A        %7D catch (IOException e
+    String body = decode(tokenParts%5B1%5D);%0D%0A        return JsonUtil.convertJsonToMap(body);%0D%0A    %7D%0D%0A%0D%0A    private static String decode(String string
 ) %7B%0D
@@ -3164,89 +3164,120 @@
     
-  
-  // Do nothing%0D%0A        %7D%0D%0A        return (JsonUtil.convertJsonToMap(userJson)
+Decoder decoder = Base64.getDecoder();%0D%0A        return new String(decoder.decode(string), StandardCharsets.UTF_8
 );%0D%0A

Refactor parsing method in TokenUtil