0

I don't understand why this simple method does not work

My class AccessChecker has the attribute Hashtable<String, List<Permission>> permissions = new Hashtable<String, List<Permission>>(); with two methods:

First method

If I put this.permissions.containsKey(key) at the end of this method , with a good key, it works.

public void updatePermissions() {
    List<Permission> permissionsTmp = permissionRepository.findAllWithEagerRelationships();

    // clear permissions
    this.permissions = new Hashtable<>();

    // load all permissions
    for (Permission permission : permissionsTmp) {
        Profil profil = profilRepository.findOne(permission.getProfil().getId());
        permission.setProfil(profil);
        UserFonc user = userFoncRepository.findOne(permission.getUserFonc().getId());
        permission.setUserFonc(user);

        log.error("updatePermissions ** user login = " + user.getNom());

        for (WebService webService: profil.getWebServices()) {
            String key = createKeyPermissions(user.getNom().toLowerCase(), webService.getNom(), webService.getMethode());
            log.error("updatePermissions ** key = " + key);
            if (this.permissions.containsKey(key)){
                this.permissions.get(key).add(permission);
            }
            else {
                List<Permission> newPermissions = new ArrayList<>();
                newPermissions.add(permission);
                this.permissions.put(key, newPermissions);
            }

        }
    }
}

Second method

But, when I do this in method hasAccessToWebservice(), it does NOT work for the same key...

public boolean hasAccessToWebservice(HttpServletRequest request) {
    boolean hasAccess = false;

    String webservice = getServiceFromRequest(request);
    String methode = request.getMethod();
    String login = SecurityUtils.getCurrentUserLogin();
    String userAgent = request.getHeader(Constants.USER_AGENT);

    final String userLogin = SecurityUtils.getCurrentUserLogin();
    log.error("hasAccessToWebservice ** user login = " + userLogin);

    String key = createKeyPermissions(login.toLowerCase(), webservice, methode);
    log.error("hasAccessToWebservice ** key = " + key);

    log.error("hasAccessToWebservice ** element = " + this.permissions.size());

    Set t = this.permissions.keySet();
    log.error(t.toString());

    if (this.permissions.containsKey(key)) {
        log.error("hasAccessToWebservice ** key found !!");
        hasAccess = true;
    }
    return hasAccess;
}

Can you explain why?

Thank you

Simon Prickett
  • 3,838
  • 1
  • 13
  • 26
user1450740
  • 731
  • 10
  • 26
  • What does not work? Do you have an error or only you expected to have `containsKey(...) == true` and it's false? – Al-un Oct 05 '17 at 16:05
  • containsKey return always false but when I do toString on my HashTable, I see my key – user1450740 Oct 06 '17 at 07:12
  • Would you mind giving an example with data as it makes me think of [this](https://stackoverflow.com/q/5632315/4906586)? The link is also mentioning that `Hashtable` is obsolete and if you could, to switch to `HashMap`. Unrelated to problem but I see that you log everything in `log.error` but it looks like more `info` or `debug` – Al-un Oct 06 '17 at 07:21
  • I replace Hashtable by HashMap but same result. In my log, I see waht I search keey "adminvannesSetBonSAVPOST" and my HashMap contains this key (HashMap.keySet().toString()) : [admin lorientSetBonSavPOST, adminvannesGetBonSavGET, admin lorientDeleteBonSavDELETE, adminvannesSetBonSavPOST, swaroskyGetBonSavGET, admin lorientGetBonSavGET, adminvannesDeleteBonSavDELETE] – user1450740 Oct 06 '17 at 07:35
  • Changing to `HashMap` would magically resolve your problem, it was rather for the sake of being up to date. Is it normal to have `adminvannesSetBonSAVPOST` with `SAV` and `admanvannesSetBonSavPOST` with `Sav`? [String.equals() is case sensitive](https://alvinalexander.com/java/edu/qanda/pjqa00001.shtml) – Al-un Oct 06 '17 at 07:55
  • Unrelated: is it expected to have the space in key for `Lorient` but not for `Vannes`? I don't know your system so I can't raise the `data inconsistency` flag but just letting you know – Al-un Oct 06 '17 at 07:58
  • I remove space in key value but it does not works !!. I'm working on Windows 10, java 1.8 and framework jhipster – user1450740 Oct 06 '17 at 08:09
  • And how about the case sensitivity? – Al-un Oct 06 '17 at 08:13
  • euh.. I don't know. How can I do this? – user1450740 Oct 06 '17 at 08:15
  • I put key on lowercase and it works !!! Thank you :) – user1450740 Oct 06 '17 at 08:22
  • I have posted an answer for summarizing your issue and to give you some food for thought if you're interested – Al-un Oct 06 '17 at 08:57

2 Answers2

1

You need to call updatePermissions to put all the data into your permissions before running hasAccessToWebservice

If you run hasAccessToWebservice without updatePermissions, you don't have anything in the permissions list => this.permissions.containsKey(key) not work

Hung Vo
  • 299
  • 1
  • 3
1

Problem summary

To summarise the topic, the problem revolved around the key consistency:

  1. Map.containsKey(Object key) will basically check if key is among the Map.keySet() mainly by relying on Object.hashCode()
  2. Your map key class is String. If you look at String.hashCode() code, you'll see that it relies on each single character value.

    Returns a hash code for this string. The hash code for a String object is computed as

    s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

    using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.)

    Value can be found in the ASCII Table highlighting that hashCode() is case-sensitive

Solution / Improvement

  • The easiest solution is to ensure that createKeyPermissions method always produces consistent key by for interface putting everything in lowercase
  • Use a TreeMap with a comparator where the most fitted one is String.CASE_INSENSITIVE_ORDER
Al-un
  • 3,102
  • 2
  • 21
  • 40