/** Retrieving claims from the Identity Server user store with the given claim dialect */
  public Map<String, Object> getClaimsMap(OAuth2TokenValidationResponseDTO tokenResponse)
      throws OAuthSystemException {
    String tenantUser = MultitenantUtils.getTenantAwareUsername(tokenResponse.getAuthorizedUser());
    String domainName = MultitenantUtils.getTenantDomain(tokenResponse.getAuthorizedUser());
    Claim[] claims;
    try {
      claims =
          IdentityTenantUtil.getRealm(domainName, tenantUser)
              .getUserStoreManager()
              .getUserClaimValues(tenantUser, null);
    } catch (Exception e) {
      throw new OAuthSystemException("Error while reading user claims for the user " + tenantUser);
    }

    String claimDialect =
        EndpointUtil.getOAuthServerConfiguration().getOpenIDConnectUserInfoEndpointClaimDialect();
    Map<String, Object> dialectClaims = new HashMap<String, Object>();
    // lets always return the sub claim
    dialectClaims.put("sub", tenantUser);
    // add only the claims with the requested dialect
    for (Claim curClaim : claims) {
      if (curClaim.getClaimUri().contains(claimDialect)) {
        dialectClaims.put(curClaim.getClaimUri(), curClaim.getValue());
      }
    }
    return dialectClaims;
  }
  /**
   * Returns an array of claims of the authorized user. This is for the OpenIDConnect user-end-point
   * implementation.
   *
   * <p>TODO : 1. Should return the userinfo response instead. TODO : 2. Should create another
   * service API for userinfo endpoint
   *
   * @param accessTokenIdentifier
   * @return
   * @throws IdentityException
   */
  public Claim[] getUserClaims(String accessTokenIdentifier) {

    OAuth2TokenValidationRequestDTO reqDTO = new OAuth2TokenValidationRequestDTO();
    OAuth2TokenValidationRequestDTO.OAuth2AccessToken accessToken = reqDTO.new OAuth2AccessToken();
    accessToken.setTokenType("bearer");
    accessToken.setIdentifier(accessTokenIdentifier);
    reqDTO.setAccessToken(accessToken);
    OAuth2TokenValidationResponseDTO respDTO = new OAuth2TokenValidationService().validate(reqDTO);

    String username = respDTO.getAuthorizedUser();
    if (username == null) { // invalid token
      log.debug(respDTO.getErrorMsg());
      return new Claim[0];
    }
    String[] scope = respDTO.getScope();
    boolean isOICScope = false;
    for (String curScope : scope) {
      if ("openid".equals(curScope)) {
        isOICScope = true;
      }
    }
    if (!isOICScope) {
      log.error("AccessToken does not have the openid scope");
      return new Claim[0];
    }

    // TODO : this code is ugly
    String profileName = "default"; // TODO : configurable
    String tenantDomain = MultitenantUtils.getTenantDomain(username);
    String tenatUser = MultitenantUtils.getTenantAwareUsername(username);

    List<Claim> claimsList = new ArrayList<Claim>();

    // MUST claim
    // http://openid.net/specs/openid-connect-basic-1_0-22.html#id_res
    Claim subClaim = new Claim();
    subClaim.setClaimUri("sub");
    subClaim.setValue(username);
    claimsList.add(subClaim);

    try {
      UserStoreManager userStore =
          IdentityTenantUtil.getRealm(tenantDomain, tenatUser).getUserStoreManager();
      // externel configured claims
      String[] claims = OAuthServerConfiguration.getInstance().getSupportedClaims();
      if (claims != null) {
        Map<String, String> extClaimsMap =
            userStore.getUserClaimValues(username, claims, profileName);
        for (Map.Entry<String, String> entry : extClaimsMap.entrySet()) {
          Claim curClaim = new Claim();
          curClaim.setClaimUri(entry.getKey());
          curClaim.setValue(entry.getValue());
          claimsList.add(curClaim);
        }
      }
      // default claims
      String[] defaultClaims = new String[3];
      defaultClaims[0] = "http://wso2.org/claims/emailaddress";
      defaultClaims[1] = "http://wso2.org/claims/givenname";
      defaultClaims[2] = "http://wso2.org/claims/lastname";
      String emailAddress = null;
      String firstName = null;
      String lastName = null;
      Map<String, String> defClaimsMap =
          userStore.getUserClaimValues(username, defaultClaims, profileName);
      if (defClaimsMap.get(defaultClaims[0]) != null) {
        emailAddress = defClaimsMap.get(defaultClaims[0]);
        Claim email = new Claim();
        email.setClaimUri("email");
        email.setValue(emailAddress);
        claimsList.add(email);
        Claim prefName = new Claim();
        prefName.setClaimUri("preferred_username");
        prefName.setValue(emailAddress.split("@")[0]);
        claimsList.add(prefName);
      }
      if (defClaimsMap.get(defaultClaims[1]) != null) {
        firstName = defClaimsMap.get(defaultClaims[1]);
        Claim givenName = new Claim();
        givenName.setClaimUri("given_name");
        givenName.setValue(firstName);
        claimsList.add(givenName);
      }
      if (defClaimsMap.get(defaultClaims[2]) != null) {
        lastName = defClaimsMap.get(defaultClaims[2]);
        Claim familyName = new Claim();
        familyName.setClaimUri("family_name");
        familyName.setValue(lastName);
        claimsList.add(familyName);
      }
      if (firstName != null && lastName != null) {
        Claim name = new Claim();
        name.setClaimUri("name");
        name.setValue(firstName + " " + lastName);
        claimsList.add(name);
      }

    } catch (Exception e) {
      log.error("Error while reading user claims ", e);
    }

    Claim[] allClaims = new Claim[claimsList.size()];
    for (int i = 0; i < claimsList.size(); i++) {
      allClaims[i] = claimsList.get(i);
    }
    return allClaims;
  }