gt:         ArrayList<String> l=new ArrayList<String>();
context: package org.yamcs.security;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Hashtable;
  import java.util.concurrent.CompletableFuture;
  
  import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.yamcs.ConfigurationException;
  import org.yamcs.YConfiguration;
  import org.yamcs.api.artemis.YamcsSession;
  import org.yamcs.utils.YObjectLoader;
  import org.yamcs.xtce.MdbMappings;
  import org.yamcs.xtce.SequenceContainer;
  import org.yamcs.xtce.XtceDb;
  import org.yamcs.xtceproc.XtceDbFactory;
  
  import io.netty.channel.ChannelHandlerContext;
  import io.netty.handler.codec.http.HttpRequest;
  
  
  /**
   * Implements privileges loaded and short-term cached from realm.
   *
   * Extending classes provide concrete method to identify the user, which this
   * class then uses to load privileges. This class also provides methods to
   * extract a username from a supplied certificate.
   *
   * Requests are usually made in short bursts, so privileges loaded from realm
   * are cached for a short period to reduce load on the realm service and retain
   * responsiveness.
   *
   * @author nm
   */
  public class Privilege {
  
      public enum SystemPrivilege {
          MayControlProcessor,
          MayModifyCommandHistory,
          MayControlCommandQueue,
          MayCommand,
          MayGetMissionDatabase,
          MayControlArchiving,
          MayControlServices,
          MayReadTables,
          MayWriteTables,
      }
  
      private static String authModuleName;
      public static boolean usePrivileges = true;
      private static String defaultUser; // Only if !usePrivileges. Could eventually replace usePrivileges i guess
  
      private static AuthModule authModule;
      private static ActiveMQSecurityManager artemisAuthModule;
      
      static final Hashtable<String, String> contextEnv = new Hashtable<>();
  
      public static int maxNoSessions;
      public static Privilege instance;
      static Logger log = LoggerFactory.getLogger(Privilege.class);
  
      public enum Type {
          SYSTEM, TC, TM_PACKET, TM_PARAMETER, TM_PARAMETER_SET
      }
  
      /**
       * Load configuration once only.
       */
      static {
          defaultUser = "admin";
          maxNoSessions = 10;
          usePrivileges = false;
          if (YConfiguration.isDefined("privileges")) {
              try {
                  YConfiguration conf=YConfiguration.getConfiguration("privileges");
                  if (conf.containsKey("maxNoSessions")) {
                      maxNoSessions=conf.getInt("maxNoSessions");
                  }
                  usePrivileges=conf.getBoolean("enabled");
  
                  if(usePrivileges) {
                      authModule = YObjectLoader.loadObject(conf.getMap("authModule"));
                      authModuleName = authModule.getClass().getName();
                      
                      if(conf.containsKey("artemisAuthModule")) {
                          artemisAuthModule = YObjectLoader.loadObject(conf.getMap("artemisAuthModule"));
                      }
                      
                  } else {
                      if (conf.containsKey("defaultUser")) {
                          String defaultUserString = conf.getString("defaultUser");
                          if (defaultUserString.isEmpty() || defaultUserString.contains(":")) {
                              throw new ConfigurationException("Invalid name '" + defaultUserString + "' for default user");
                          }
                          defaultUser = defaultUserString;
                      }
                  }
              } catch (IOException|ConfigurationException e) {
                  throw new ConfigurationException("Failed to load 'privileges' configuration", e);
              }
          }
  
          if(usePrivileges) {
              log.info("Privileges enabled, authenticating and authorising by module {}", authModule);
          } else {
              log.warn("Privileges disabled, all connections are allowed and have full permissions");
          }
      }
      public String[] getRoles(final AuthenticationToken authenticationToken) throws InvalidAuthenticationToken {
          if(!usePrivileges){
              return null;
          }
          
          return authModule.getRoles(authenticationToken);
      }
   
  
      /**
       * loads the configuration of the privilege. If privileges.enabled is not
       * set to false in the privileges.properties, then load the privileges from
       * the LDAP.
       *
       * @throws ConfigurationException
       *             when the privileges.enabled is not set to false and the ldap
       *             parammeters are not present
       */
      protected Privilege() throws ConfigurationException {
      }
  
      public static synchronized Privilege getInstance() {
          if (instance == null)
              instance = new Privilege() {};
  
          return instance;
      }
  
      /**
       *
       * @return true if privileges are enabled
       */
      public boolean isEnabled() {
          return usePrivileges;
      }
  
  
      /**
       * Convenience method, check if user has specific role.
       * @param authenticationToken 
       *
       * @param role Title or full dn.
       * @return True if usePrivileges enabled and user has role, false otherwise.
       * @throws InvalidAuthenticationToken 
       */
      public boolean hasRole(final AuthenticationToken authenticationToken, String role ) throws InvalidAuthenticationToken {
          if(!usePrivileges) {
              return false;
          }
          
          if(authenticationToken == null || authenticationToken.getPrincipal() == null) {
              return false;
          }
          if (isSystemToken(authenticationToken)) {
              return true;
          }
  
          return authModule.hasRole(authenticationToken, role);
      }
  
      private boolean isSystemToken(final AuthenticationToken authenticationToken) {
          return authenticationToken.getPrincipal().equals(YamcsSession.hornetqInvmUser) || (authenticationToken instanceof SystemToken);
      }
  
      /**
       *
       * @param authenticationToken 
       * @param type
       * @param privilege
       *            a opsname of tc, tm parameter or tm packet
       * @return true if the privilege is known and the current user has it.
       * @throws InvalidAuthenticationToken 
       */
      public boolean hasPrivilege(final AuthenticationToken authenticationToken, Type type, String privilege) throws InvalidAuthenticationToken  {
          if (!usePrivileges) {
              return true;
          }
          
          if(authenticationToken == null || authenticationToken.getPrincipal() == null) {
              return false;
          }
  
          if (isSystemToken(authenticationToken)) {
              return true;
          }
  
          return authModule.hasPrivilege(authenticationToken, type, privilege);
      }
      /**
       * Like the method above but instead of throwing InvalidAuthenticationToken, it returns false in case the token is not valid.
       * 
       * To be used to avoid dealing with the exception in case we know that the token must be valid (i.e. immediately after a authenticate)
       * 
       * @param authenticationToken
       * @param type
       * @param privilege
       * @return true if the user has the system privilege
       */
      public boolean hasPrivilege1(final AuthenticationToken authenticationToken, Type type, String privilege) {
          try {
              return hasPrivilege(authenticationToken, type, privilege);
          } catch (InvalidAuthenticationToken e) {
              return false;
          }
      }
      
      /**
       * 
       * @param authenticationToken
       * @param privilege
       * @return true if the user has the system privilege
       * @throws InvalidAuthenticationToken
       */
      public boolean hasPrivilege(final AuthenticationToken authenticationToken, SystemPrivilege privilege) throws InvalidAuthenticationToken {
          if (!usePrivileges)     return true;
          if(authenticationToken == null || authenticationToken.getPrincipal() == null) return false;
  
          if (isSystemToken(authenticationToken)) return true;
      
          return hasPrivilege(authenticationToken, Type.SYSTEM, privilege.name());
      }
      
      /**
       * Like above but instead of throwing InvalidAuthenticationToken, it returns false if the token is not valid. 
       * 
       * @param authToken
       * @param sysPrivilege
       * @return true if the user has the system privilege
       */
      public boolean hasPrivilege1(AuthenticationToken authToken, SystemPrivilege sysPrivilege) {
          try {
              return hasPrivilege(authToken, sysPrivilege);
          } catch (InvalidAuthenticationToken e) {
              return false;
          }
      }
  
     
      
      public static String getAuthModuleName() {
          return authModuleName;
      }
      
      
  
      /**
       * Returns the default user if this server is unsecured. Returns null in all other cases.
       * @return default username
       */
      public static String getDefaultUser() {
          return defaultUser;
      }
  
      /**
       * Get packet names this user has appropriate privileges for.
       *
       * @param yamcsInstance Used to get MDB.
       * @param authToken 
       * @param namespace If null defaults to "MDB:OPS Name"
       * @return A collection of TM packet names in the specified namespace for
       * which the user has privileges.
       * @throws ConfigurationException
       * @throws InvalidAuthenticationToken 
       */
      public Collection<String> getTmPacketNames(String yamcsInstance, final AuthenticationToken authToken, String namespace) throws ConfigurationException, InvalidAuthenticationToken {
          if( namespace == null ) {
              namespace = MdbMappings.MDB_OPSNAME;
          }
          Collection<String> tl= getTmPacketNames(XtceDbFactory.getInstance(yamcsInstance), namespace);
          ArrayList<String> l=new ArrayList<String>();
          for(String name:tl) {
              if(!hasPrivilege(authToken, Privilege.Type.TM_PACKET, name)){
                  continue;
              }
              l.add(name);
          }
          return l;
      }
      
      private Collection<String> getTmPacketNames(XtceDb xtcedb, String namespace) {
          ArrayList<String> pn=new ArrayList<String>();
          for(SequenceContainer sc:xtcedb.getSequenceContainers()){
              String alias=sc.getAlias(namespace);
              if(alias!=null){
                  pn.add(alias);
              }
          }
          return pn;
      }
      /**
       * Get parameter names this user has appropriate privileges for.
       *
       * @param yamcsInstance Used to get MDB.
       * @param authToken 
       * @param namespace If null defaults to "MDB:OPS Name"
       * @return A collection of TM parameter names in the specified namespace for
       * which the user has privileges.
       * @throws ConfigurationException
       * @throws InvalidAuthenticationToken 
       */
      public Collection<String> getTmParameterNames(String yamcsInstance, final AuthenticationToken authToken, String namespace) throws ConfigurationException, InvalidAuthenticationToken {
          if( namespace == null ) {
              namespace = MdbMappings.MDB_OPSNAME;
          }
          XtceDb xtcedb = XtceDbFactory.getInstance(yamcsInstance);
  