# VariablePool.java

    /*
    ** Module   : VariablePool.java
    ** Abstract : implements variables for access rights expressions
    **
    ** Copyright (c) 2005-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 NVS 20050323 NEW   @20461 Created the initial version. This class
    **                               implements SecurityManager variables that may
    **                               be used in access rights expressions.
    ** 002 NVS 20050411 CHG   @20677 Fixed few javadoc issues
    ** 003 NVS 20050414 CHG   @20732 Added handling for the RestrictedUseException
    ** 004 NVS 20050418 CHG   @20769 New Notifiable required dummy initEIR().
    ** 005 GES 20060305 CHG   @24896 Logging level changes.
    ** 006 GES 20070111 CHG   @31802 Removed use of notifiable (it was an over-
    **                               complicated approach).
    ** 007 EVL 20070609 CHG   @34005 Adding explicit import of the class
    **                               com.goldencode.p2j.net.Queue to eliminate
    **                               conflict with the same class from java.util
    **                               package to be able to compile for Java 6.
    ** 008 ECF 20071106 CHG   @35903 Eliminated references to network Queue class.
    **                               Replaced with SessionManager API calls.
    ** 009 GES 20081027 CHG   @40344 Some cleanups to eliminate direct socket use.
    **                               Added isSecureConnection() variable.
    ** 010 GBB 20230512              Logging methods replaced by CentralLogger/ConversionStatus.
    ** 011 GBB 20230825              SecurityManager session method call updated.
    ** 012 GBB 20240313              Session renamed to SecuritySession to resolve ambigious imports.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.security;

    import java.util.*;
    import java.text.*;
    import java.net.*;
    import com.goldencode.p2j.net.*;
    import com.goldencode.p2j.directory.*;

    /* TODO:
     * 1. there is a great deal of cut and paste duplication throughout this file
     *    (which is unnecessary), most likely there should be some new helpers in
     *    the security manager for the common stuff, but if this class is really
     *    the ONLY place the helpers would be used, then some private methods can
     *    be added to centralize an implementation
     * 2. the expression engine's data type limits no longer exist so the API can
     *    be simplified a bit (e.g. get rid of use of long where possible and use
     *    an int instead)
     */

    /**
     * Implements Security Manager variables that may be used in access rights
     * expressions.
     */
    public class VariablePool
    {
       /**
        * Constructor.
        */
       public VariablePool()
       {
       }

       /**
        * Gets the current application ID.
        *
        * @return current application ID
        */
       public String getAppId()
       {
          SecurityCache sc = SecurityManager.getInstance().getCache();
          SecurityContextStack ctx = SecurityContextStack.getContext();

          if (ctx == null)
             return "";

          int id = ctx.getIdList()[0];

          if (id == -1)
             return "";
          else
             return sc.getAccountByOrd(id).getSubjectId();
       }

       /**
        * Gets the current user ID.
        *
        * @return current user ID
        */
       public String getUserId()
       {
          SecurityCache sc = SecurityManager.getInstance().getCache();
          SecurityContextStack ctx = SecurityContextStack.getContext();

          if (ctx == null)
             return "";

          int id = ctx.getIdList()[1];

          if (id == -1)
             return "";
          else
             return sc.getAccountByOrd(id).getSubjectId();
       }

       /**
        * Gets the number of groups.
        *
        * @return number of groups
        */
       public long getGroups()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return 0;

          int[] idList = ctx.getIdList();
          return idList.length - 2;
       }

       /**
        * Gets the first defined group ID.
        *
        * @return the first defined group ID
        */
       public String getGroupId()
       {
          SecurityCache sc = SecurityManager.getInstance().getCache();
          SecurityContextStack ctx = SecurityContextStack.getContext();

          if (ctx == null)
             return "";

          int[] idList = ctx.getIdList();

          if (idList.length == 2)
             return "";
          else
             return sc.getAccountByOrd(idList[2]).getSubjectId();
       }

       /**
        * Gets a group name by index.
        *
        * @param i
        *        index of the group name to get
        * @return indexed group name
        */
       public String getGroup(long i)
       {
          SecurityCache sc = SecurityManager.getInstance().getCache();
          SecurityContextStack ctx = SecurityContextStack.getContext();

          if (ctx == null)
             return "";

          int[] idList = ctx.getIdList();

          if (2 + i >= idList.length)
             return "";
          else
             return sc.getAccountByOrd(idList[2 + (int)i]).getSubjectId();
       }

       /**
        * Gets the TLS peer name.
        *
        * @return TLS peer name
        */
       public String getPeerName()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return "";

          NetSocket   nsock = getSocket(ctx);
          InetAddress peer  = nsock.getRemoteAddr();

          return peer.getHostName();
       }

       /**
        * Gets the TLS server name.
        *
        * @return TLS server name
        */
       public String getServerName()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return "";

          NetSocket   nsock = getSocket(ctx);
          InetAddress serv  = nsock.getLocalAddr();

          return serv.getHostName();
       }

       /**
        * Gets the TLS peer IP address.
        *
        * @return TLS peer IP address
        */
       public String getPeerIp()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return "";

          NetSocket   nsock = getSocket(ctx);
          InetAddress peer  = nsock.getRemoteAddr();

          return peer.getHostAddress();
       }

       /**
        * Gets the TLS server IP address.
        *
        * @return TLS server IP address
        */
       public String getServerIp()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return "";

          NetSocket   nsock = getSocket(ctx);
          InetAddress serv  = nsock.getLocalAddr();

          return serv.getHostAddress();
       }

       /**
        * Gets the secure status of the socket in use for this session.
        *
        * @return   <code>true</code> if the socket is based on SSL/TLS and
        *           <code>false</code> if the socket is insecure.
        */
       public boolean isSecureConnection()
       {
          SecurityContextStack ctx = getContext();

          if (ctx == null)
             return false;

          NetSocket nsock = getSocket(ctx);

          return (nsock.getSession() != null);
       }

       /**
        * Gets the TLS P2J peer node address.
        *
        * @return  TLS P2J peer node address, or 0 if there is no network session
        *          for the current context.
        */
       public long getPeerNode()
       {
          return SessionManager.get().getNodeAddress();
       }

       /**
        * Gets the TLS P2J server node address.
        *
        * @return  TLS P2J server node address, or 0 if there is no network
        *          session for the current context.
        */
       public long getServerNode()
       {
          return SessionManager.get().getRemoteAddress();
       }

       /**
        * Gets the current date as "YYYY/MM/DD".
        *
        * @return current date
        */
       public String getDate()
       {
          Date date = new Date();
          DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
          StringBuffer b = new StringBuffer();

          df.format(date, b, new FieldPosition(DateFormat.YEAR_FIELD));
          return new String(b);
       }

       /**
        * Gets the current year.
        *
        * @return current year
        */
       public long getYear()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.YEAR);
       }

       /**
        * Gets the current month.
        *
        * @return current month
        */
       public long getMonth()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.MONTH) + 1;
       }

       /**
        * Gets the current day of the month.
        *
        * @return current day of the month
        */
       public long getDayOfMonth()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.DATE);
       }

       /**
        * Gets the current day of the year.
        *
        * @return current day of the year
        */
       public long getDayOfYear()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.DAY_OF_YEAR);
       }

       /**
        * Gets the current day of the epoch.
        *
        * @return current day of the epoch
        */
       public long getDayOfEpoch()
       {
          Date date = new Date();
          return date.getTime() / 1000 / 86400;
       }

       /**
        * Gets the current day of the week.
        *
        * @return current day of the week
        */
       public long getWeekDay()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.DAY_OF_WEEK);
       }

       /**
        * Gets the current week number.
        *
        * @return current week number
        */
       public long getWeekNum()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.WEEK_OF_YEAR);
       }

       /**
        * Checks whether today is a holiday.
        *
        * @return <code>true</code> if today is a public holiday
        */
       public boolean isHoliday()
       {
          // Safely query cached data
          SecurityCache sc = SecurityManager.getInstance().getCache();

          DateValue today = new DateValue();

          return sc.getHolidays().contains(today.toString());
       }

       /**
        * Gets the current time of day.
        *
        * @return current time of day
        */
       public String getTime()
       {
          Date date = new Date();
          DateFormat df = new SimpleDateFormat("HH/mm/ss");
          StringBuffer b = new StringBuffer();

          df.format(date, b, new FieldPosition(DateFormat.HOUR_OF_DAY0_FIELD));
          return new String(b);
       }

       /**
        * Gets the current hour for 12 hour clock.
        *
        * @return current hour for 12 hour clock
        */
       public long getHourAmPm()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.HOUR);
       }

       /**
        * Gets the current hour for 24 hour clock.
        *
        * @return current hour for 24 hour clock
        */
       public long getHour()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.HOUR_OF_DAY);
       }

       /**
        * Gets the current minute.
        *
        * @return current minute
        */
       public long getMinute()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.MINUTE);
       }

       /**
        * Gets the current second.
        *
        * @return current second
        */
       public long getSecond()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.SECOND);
       }

       /**
        * Gets the current minute since midnight.
        *
        * @return current minute since midnight
        */
       public long getMinSinceMidnight()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.MINUTE) + cal.get(Calendar.HOUR_OF_DAY) * 60;
       }

       /**
        * Gets the current second since midnight.
        *
        * @return current second since midnight
        */
       public long getSecSinceMidnight()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.SECOND) +
             (cal.get(Calendar.MINUTE) + cal.get(Calendar.HOUR_OF_DAY) * 60) * 60;
       }

       /**
        * Checks whether it is AM time.
        *
        * @return <code>true</code> if it is AM time.
        */
       public boolean isAm()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.AM_PM) == Calendar.AM;
       }

       /**
        * Checks whether it is PM time.
        *
        * @return <code>true</code> if it is PM time.
        */
       public boolean isPm()
       {
          Calendar cal = Calendar.getInstance();
          return cal.get(Calendar.AM_PM) == Calendar.PM;
       }

       /**
        * Reads a single (the first) string value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @return attribute value
        */
       public String dirS(String oid, String attrName)
       {
          return dirS(oid, attrName, 0);
       }

       /**
        * Reads a single indexed string value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @param i
        *        index of the particular value to read
        * @return attribute value
        */
       public String dirS(String oid, String attrName, long i)
       {
          // accessing directory
          DirectoryService ds = DirectoryService.getInstance();

          ds.bind();
          String value = ds.getNodeString(oid, attrName, (int)i);
          ds.unbind();

          return value;
       }

       /**
        * Reads a single (the first) integer value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @return attribute value
        */
       public long dirL(String oid, String attrName)
       {
          return dirL(oid, attrName, 0);
       }

       /**
        * Reads a single indexed integer value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @param i
        *        index of the particular value to read
        * @return attribute value
        */
       public long dirL(String oid, String attrName, long i)
       {
          // accessing directory
          DirectoryService ds = DirectoryService.getInstance();

          ds.bind();
          Integer value = ds.getNodeInteger(oid, attrName, (int)i);
          ds.unbind();

          return value == null ? 0 : value.intValue();
       }

       /**
        * Reads a single (the first) boolean value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @return attribute value
        */
       public boolean dirB(String oid, String attrName)
       {
          return dirB(oid, attrName, 0);
       }

       /**
        * Reads a single indexed boolean value from a P2J directory attribute.
        *
        * @param oid
        *        directory object id to query
        * @param attrName
        *        attribute name to read
        * @param i
        *        index of the particular value to read
        * @return attribute value
        */
       public boolean dirB(String oid, String attrName, long i)
       {
          // accessing directory
          DirectoryService ds = DirectoryService.getInstance();

          ds.bind();
          Boolean value = ds.getNodeBoolean(oid, attrName, (int)i);
          ds.unbind();

          return value == null ? false : value.booleanValue();
       }

       /**
        * Safely query the cached security context.
        *
        * @return   The security context or <code>null</code> if there is no
        *           context available.
        */
       private SecurityContextStack getContext()
       {
          SecurityCache sc = SecurityManager.getInstance().getCache();

          return SecurityContextStack.getContext();
       }

       /**
        * Access the network state associated with the current security context.
        *
        * @param    ctx
        *           The current session's security context.
        *
        * @return   The socket associated with the remote connection.
        */
       private NetSocket getSocket(SecurityContextStack ctx)
       {
          SecurityContext key = ctx.getSessionKey();
          SecuritySession sess = SecurityManager.getInstance().sessionSm.locateSession(key);
          Object sessid = sess.getSessionId();
          return (NetSocket) sessid;
       }
    }