From 15ce7c5bab781592cdd81a736ad530341e0fdfeb Mon Sep 17 00:00:00 2001 From: Troy Murray Date: Tue, 26 Jun 2018 14:09:23 -0400 Subject: [PATCH] change OS X to macOS (#41294) * change OS X to macOS +label: docsite_pr * Update all Mac OS X references to be macOS * Drop extra Mac --- .../dev_guide/testing/sanity/integration-aliases.rst | 2 +- .../rst/installation_guide/intro_installation.rst | 8 ++++---- docs/docsite/rst/plugins/callback.rst | 4 ++-- docs/docsite/rst/reference_appendices/faq.rst | 4 ++-- docs/docsite/rst/roadmap/ROADMAP_2_2.rst | 6 +++--- docs/docsite/rst/roadmap/ROADMAP_2_3.rst | 4 ++-- docs/docsite/rst/scenario_guides/guide_gce.rst | 2 +- .../docsite/rst/user_guide/intro_getting_started.rst | 2 +- hacking/env-setup | 12 ++++++------ lib/ansible/module_utils/facts/network/darwin.py | 2 +- .../module_utils/facts/network/generic_bsd.py | 2 +- lib/ansible/module_utils/urls.py | 6 +++--- lib/ansible/modules/files/stat.py | 2 +- lib/ansible/modules/system/group.py | 2 +- lib/ansible/modules/system/osx_defaults.py | 6 +++--- lib/ansible/modules/system/user.py | 10 +++++----- lib/ansible/parsing/vault/__init__.py | 2 +- lib/ansible/plugins/callback/osx_say.py | 4 ++-- lib/ansible/plugins/filter/core.py | 2 +- test/integration/targets/tags/runme.sh | 2 +- test/runner/injector/injector.py | 2 +- .../modules/network/f5/fixtures/load_ltm_irules.json | 4 ++-- 22 files changed, 45 insertions(+), 45 deletions(-) diff --git a/docs/docsite/rst/dev_guide/testing/sanity/integration-aliases.rst b/docs/docsite/rst/dev_guide/testing/sanity/integration-aliases.rst index ed20a162080..3e15ee67090 100644 --- a/docs/docsite/rst/dev_guide/testing/sanity/integration-aliases.rst +++ b/docs/docsite/rst/dev_guide/testing/sanity/integration-aliases.rst @@ -39,7 +39,7 @@ Skipping Aliases can be used to skip platforms using one of the following: - ``skip/freebsd`` - Skip tests on FreeBSD. -- ``skip/osx`` - Skip tests on macOS / OS X. +- ``skip/osx`` - Skip tests on macOS. - ``skip/rhel`` - Skip tests on RHEL. Aliases can be used to skip Python major versions using one of the following: diff --git a/docs/docsite/rst/installation_guide/intro_installation.rst b/docs/docsite/rst/installation_guide/intro_installation.rst index 8f59238d63f..17575dc7e97 100644 --- a/docs/docsite/rst/installation_guide/intro_installation.rst +++ b/docs/docsite/rst/installation_guide/intro_installation.rst @@ -43,11 +43,11 @@ Control Machine Requirements Currently Ansible can be run from any machine with Python 2 (versions 2.6 or 2.7) or Python 3 (versions 3.5 and higher) installed (Windows isn't supported for the control machine). -This includes Red Hat, Debian, CentOS, OS X, any of the BSDs, and so on. +This includes Red Hat, Debian, CentOS, macOS, any of the BSDs, and so on. .. note:: - Mac OS X by default is configured for a small number of file handles, so if you want to use 15 or more forks you'll need to raise the ulimit with ``sudo launchctl limit maxfiles unlimited``. This command can also fix any "Too many open files" error. + macOS by default is configured for a small number of file handles, so if you want to use 15 or more forks you'll need to raise the ulimit with ``sudo launchctl limit maxfiles unlimited``. This command can also fix any "Too many open files" error. .. warning:: @@ -221,7 +221,7 @@ Latest Releases on Mac OSX The preferred way to install Ansible on a Mac is via pip. -The instructions can be found in `Latest Releases Via Pip`_ section. If you are running macOS/OS X version 10.12 or older, then you ought to upgrade to the latest pip (9.0.3 or newer) to connect to the Python Package Index securely. +The instructions can be found in `Latest Releases Via Pip`_ section. If you are running macOS version 10.12 or older, then you ought to upgrade to the latest pip (9.0.3 or newer) to connect to the Python Package Index securely. .. _from_pkgutil: @@ -266,7 +266,7 @@ Or if you are looking for the latest development version:: $ pip install git+https://github.com/ansible/ansible.git@devel -If you are installing on OS X Mavericks, you may encounter some noise from your compiler. A workaround is to do the following:: +If you are installing on macOS Mavericks, you may encounter some noise from your compiler. A workaround is to do the following:: $ sudo CFLAGS=-Qunused-arguments CPPFLAGS=-Qunused-arguments pip install ansible diff --git a/docs/docsite/rst/plugins/callback.rst b/docs/docsite/rst/plugins/callback.rst index 425d2ad6dd9..2ad160628d9 100644 --- a/docs/docsite/rst/plugins/callback.rst +++ b/docs/docsite/rst/plugins/callback.rst @@ -16,7 +16,7 @@ Example Callback Plugins The :doc:`_plays ` callback is an example of how to record playbook events to a log file, and the :doc:`mail ` callback sends email on playbook failures. -The :doc:`osx_say ` callback responds with computer synthesized speech on OS X in relation to playbook events. +The :doc:`osx_say ` callback responds with computer synthesized speech on macOS in relation to playbook events. .. _enabling_callbacks: @@ -75,7 +75,7 @@ You can also set this as an environment variable: Plugin List +++++++++++ -You can use ``ansible-doc -t callback -l`` to see the list of available plugins. +You can use ``ansible-doc -t callback -l`` to see the list of available plugins. Use ``ansible-doc -t callback `` to see specific documents and examples. diff --git a/docs/docsite/rst/reference_appendices/faq.rst b/docs/docsite/rst/reference_appendices/faq.rst index c02321708b3..fff28f665ed 100644 --- a/docs/docsite/rst/reference_appendices/faq.rst +++ b/docs/docsite/rst/reference_appendices/faq.rst @@ -377,9 +377,9 @@ The mkpasswd utility that is available on most Linux systems is a great option: .. code-block:: shell-session mkpasswd --method=sha-512 - -If this utility is not installed on your system (e.g. you are using OS X) then you can still easily + +If this utility is not installed on your system (e.g. you are using macOS) then you can still easily generate these passwords using Python. First, ensure that the `Passlib `_ password hashing library is installed: diff --git a/docs/docsite/rst/roadmap/ROADMAP_2_2.rst b/docs/docsite/rst/roadmap/ROADMAP_2_2.rst index cdaff85a8f3..c54124a9db7 100644 --- a/docs/docsite/rst/roadmap/ROADMAP_2_2.rst +++ b/docs/docsite/rst/roadmap/ROADMAP_2_2.rst @@ -230,10 +230,10 @@ Another note from Jason M: A lot of this work is to ease the burden of CI, CI pe **Done:** Windows integration tests now run on Shippable. - - FreeBSD - Include FreeBSD in CI coverage. Not originally on the roadmap, this is an intermediary step for CI coverage for OS X. + - FreeBSD - Include FreeBSD in CI coverage. Not originally on the roadmap, this is an intermediary step for CI coverage for macOS. **Done:** FreeBSD integration tests now run on Shippable. - - OS X - Include OS X in CI coverage. + - macOS - Include macOS in CI coverage. - **Done:** OS X integration tests now run on Shippable. + **Done:** macOS integration tests now run on Shippable. diff --git a/docs/docsite/rst/roadmap/ROADMAP_2_3.rst b/docs/docsite/rst/roadmap/ROADMAP_2_3.rst index af0d7866f26..de2890b89ed 100644 --- a/docs/docsite/rst/roadmap/ROADMAP_2_3.rst +++ b/docs/docsite/rst/roadmap/ROADMAP_2_3.rst @@ -118,9 +118,9 @@ Lead by mattclay Some new issues have also appeared, which are currently being worked on. -- *Enable Remaining Tests:* Implement fixes for OS X, FreeBSD and Python 3 to enable the remaining blacklisted tests for CI. +- *Enable Remaining Tests:* Implement fixes for macOS, FreeBSD and Python 3 to enable the remaining blacklisted tests for CI. - **Ongoing:** More tests have been enabled for OS X, FreeBSD and Python 3. However, work still remains to enable more tests. + **Ongoing:** More tests have been enabled for macOS, FreeBSD and Python 3. However, work still remains to enable more tests. - *Windows Server 2016:* Add Windows Server 2016 to CI when official AMIs become available. diff --git a/docs/docsite/rst/scenario_guides/guide_gce.rst b/docs/docsite/rst/scenario_guides/guide_gce.rst index 3654c4e6a14..a15f01f9dd2 100644 --- a/docs/docsite/rst/scenario_guides/guide_gce.rst +++ b/docs/docsite/rst/scenario_guides/guide_gce.rst @@ -17,7 +17,7 @@ The GCE modules all require the apache-libcloud module which you can install fro $ pip install apache-libcloud -.. note:: If you're using Ansible on Mac OS X, libcloud also needs to access a CA cert chain. You'll need to download one (you can get one for `here `_.) +.. note:: If you're using Ansible on macOS, libcloud also needs to access a CA cert chain. You'll need to download one (you can get one for `here `_.) Credentials ----------- diff --git a/docs/docsite/rst/user_guide/intro_getting_started.rst b/docs/docsite/rst/user_guide/intro_getting_started.rst index 78477e82860..9e7a025a784 100644 --- a/docs/docsite/rst/user_guide/intro_getting_started.rst +++ b/docs/docsite/rst/user_guide/intro_getting_started.rst @@ -28,7 +28,7 @@ machines over SSH. By default, Ansible will try to use native OpenSSH for remote communication when possible. This enables ControlPersist (a performance feature), Kerberos, and options in ``~/.ssh/config`` such as Jump Host setup. However, when using Enterprise Linux 6 operating systems as the control machine (Red Hat Enterprise Linux and derivatives such as CentOS), the version of OpenSSH may be too old to support ControlPersist. On these operating systems, Ansible will fallback into using a high-quality Python implementation of -OpenSSH called 'paramiko'. If you wish to use features like Kerberized SSH and more, consider using Fedora, OS X, or Ubuntu as your control machine until a newer version of OpenSSH is available for your platform. +OpenSSH called 'paramiko'. If you wish to use features like Kerberized SSH and more, consider using Fedora, macOS, or Ubuntu as your control machine until a newer version of OpenSSH is available for your platform. Occasionally you'll encounter a device that doesn't support SFTP. This is rare, but should it occur, you can switch to SCP mode in :ref:`intro_configuration`. diff --git a/hacking/env-setup b/hacking/env-setup index 961c6bdcc11..2b042722a65 100644 --- a/hacking/env-setup +++ b/hacking/env-setup @@ -25,7 +25,7 @@ elif [ -n "$KSH_VERSION" ] && echo $KSH_VERSION | grep -qv '^@(#)PD KSH'; then else HACKING_DIR="$PWD/hacking" fi -# The below is an alternative to readlink -fn which doesn't exist on OS X +# The below is an alternative to readlink -fn which doesn't exist on macOS # Source: http://stackoverflow.com/a/1678636 FULL_PATH=$($PYTHON_BIN -c "import os; print(os.path.realpath('$HACKING_DIR'))") export ANSIBLE_HOME="$(dirname "$FULL_PATH")" @@ -70,16 +70,16 @@ fi if [ "$verbosity" != silent ] ; then cat <<- EOF - + Setting up Ansible to run out of checkout... - + PATH=$PATH PYTHONPATH=$PYTHONPATH MANPATH=$MANPATH - + Remember, you may wish to specify your host file with -i - + Done! - + EOF fi diff --git a/lib/ansible/module_utils/facts/network/darwin.py b/lib/ansible/module_utils/facts/network/darwin.py index 4e1d4a9e3e6..90117e5360c 100644 --- a/lib/ansible/module_utils/facts/network/darwin.py +++ b/lib/ansible/module_utils/facts/network/darwin.py @@ -22,7 +22,7 @@ from ansible.module_utils.facts.network.generic_bsd import GenericBsdIfconfigNet class DarwinNetwork(GenericBsdIfconfigNetwork): """ - This is the Mac OS X/Darwin Network Class. + This is the Mac macOS Darwin Network Class. It uses the GenericBsdIfconfigNetwork unchanged """ platform = 'Darwin' diff --git a/lib/ansible/module_utils/facts/network/generic_bsd.py b/lib/ansible/module_utils/facts/network/generic_bsd.py index 3be10be25e5..f8d6867e045 100644 --- a/lib/ansible/module_utils/facts/network/generic_bsd.py +++ b/lib/ansible/module_utils/facts/network/generic_bsd.py @@ -109,7 +109,7 @@ class GenericBsdIfconfigNetwork(Network): all_ipv4_addresses=[], all_ipv6_addresses=[], ) - # FreeBSD, DragonflyBSD, NetBSD, OpenBSD and OS X all implicitly add '-a' + # FreeBSD, DragonflyBSD, NetBSD, OpenBSD and macOS all implicitly add '-a' # when running the command 'ifconfig'. # Solaris must explicitly run the command 'ifconfig -a'. rc, out, err = self.module.run_command([ifconfig_path, ifconfig_options]) diff --git a/lib/ansible/module_utils/urls.py b/lib/ansible/module_utils/urls.py index 1b02a568987..3631ab00048 100644 --- a/lib/ansible/module_utils/urls.py +++ b/lib/ansible/module_utils/urls.py @@ -248,8 +248,8 @@ if not HAS_MATCH_HOSTNAME: HAS_MATCH_HOSTNAME = True -# This is a dummy cacert provided for Mac OS since you need at least 1 -# ca cert, regardless of validity, for Python on Mac OS to use the +# This is a dummy cacert provided for macOS since you need at least 1 +# ca cert, regardless of validity, for Python on macOS to use the # keychain functionality in OpenSSL for validating SSL certificates. # See: http://mercurial.selenic.com/wiki/CACertificates#Mac_OS_X_10.6_and_higher b_DUMMY_CA_CERT = b"""-----BEGIN CERTIFICATE----- @@ -625,7 +625,7 @@ class SSLValidationHandler(urllib_request.BaseHandler): to_add_fd, to_add_path = tempfile.mkstemp() to_add = False - # Write the dummy ca cert if we are running on Mac OS X + # Write the dummy ca cert if we are running on macOS if system == u'Darwin': os.write(tmp_fd, b_DUMMY_CA_CERT) # Default Homebrew path for OpenSSL certs diff --git a/lib/ansible/modules/files/stat.py b/lib/ansible/modules/files/stat.py index 9a167f73542..bb0c38f0133 100644 --- a/lib/ansible/modules/files/stat.py +++ b/lib/ansible/modules/files/stat.py @@ -424,7 +424,7 @@ def format_output(module, path, st): ('st_ftype', 'file_type'), ('st_attrs', 'attrs'), ('st_obtype', 'object_type'), - # OS X + # macOS ('st_rsize', 'real_size'), ('st_creator', 'creator'), ('st_type', 'file_type'), diff --git a/lib/ansible/modules/system/group.py b/lib/ansible/modules/system/group.py index ce4ff8a26a2..79904ed673a 100644 --- a/lib/ansible/modules/system/group.py +++ b/lib/ansible/modules/system/group.py @@ -283,7 +283,7 @@ class DragonFlyBsdGroup(FreeBsdGroup): class DarwinGroup(Group): """ - This is a Mac OS X Darwin Group manipulation class. + This is a Mac macOS Darwin Group manipulation class. This overrides the following methods from the generic class:- - group_del() diff --git a/lib/ansible/modules/system/osx_defaults.py b/lib/ansible/modules/system/osx_defaults.py index ebf772a1532..24281ac312c 100644 --- a/lib/ansible/modules/system/osx_defaults.py +++ b/lib/ansible/modules/system/osx_defaults.py @@ -16,10 +16,10 @@ DOCUMENTATION = ''' --- module: osx_defaults author: Franck Nijhof (@frenck) -short_description: osx_defaults allows users to read, write, and delete Mac OS X user defaults from Ansible +short_description: osx_defaults allows users to read, write, and delete macOS user defaults from Ansible description: - - osx_defaults allows users to read, write, and delete Mac OS X user defaults from Ansible scripts. - Mac OS X applications and other programs use the defaults system to record user preferences and other + - osx_defaults allows users to read, write, and delete macOS user defaults from Ansible scripts. + macOS applications and other programs use the defaults system to record user preferences and other information that must be maintained when the applications aren't running (such as default font for new documents, or the position of an Info panel). version_added: "2.0" diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py index 94b3d685e82..78f3d89c166 100644 --- a/lib/ansible/modules/system/user.py +++ b/lib/ansible/modules/system/user.py @@ -41,7 +41,7 @@ options: required: false type: bool description: - - Darwin/OS X only, optionally hide the user from the login window and system preferences. + - macOS only, optionally hide the user from the login window and system preferences. - The default will be 'True' if the I(system) option is used. version_added: "2.6" non_unique: @@ -74,8 +74,8 @@ options: shell: description: - Optionally set the user's shell. - - On Mac OS X, before version 2.5, the default shell for non-system users was /usr/bin/false. - Since 2.5, the default shell for non-system users on Mac OS X is /bin/bash. + - On macOS, before version 2.5, the default shell for non-system users was /usr/bin/false. + Since 2.5, the default shell for non-system users on macOS is /bin/bash. home: description: - Optionally set the user's home directory. @@ -86,7 +86,7 @@ options: password: description: - Optionally set the user's password to this crypted value. - - On Darwin/OS X systems, this value has to be cleartext. Beware of security issues. + - On macOS systems, this value has to be cleartext. Beware of security issues. - See U(https://docs.ansible.com/ansible/faq.html#how-do-i-generate-crypted-passwords-for-the-user-module) for details on various ways to generate these password values. state: @@ -1693,7 +1693,7 @@ class SunOS(User): class DarwinUser(User): """ - This is a Darwin Mac OS X User manipulation class. + This is a Darwin macOS User manipulation class. Main differences are that Darwin:- - Handles accounts in a database managed by dscl(1) - Has no useradd/groupadd diff --git a/lib/ansible/parsing/vault/__init__.py b/lib/ansible/parsing/vault/__init__.py index 86e7d071d8a..3ac539df9aa 100644 --- a/lib/ansible/parsing/vault/__init__.py +++ b/lib/ansible/parsing/vault/__init__.py @@ -836,7 +836,7 @@ class VaultEditor: r = subprocess.call(['shred', tmp_path]) except (OSError, ValueError): # shred is not available on this system, or some other error occurred. - # ValueError caught because OS X El Capitan is raising an + # ValueError caught because macOS El Capitan is raising an # exception big enough to hit a limit in python2-2.7.11 and below. # Symptom is ValueError: insecure pickle when shred is not # installed there. diff --git a/lib/ansible/plugins/callback/osx_say.py b/lib/ansible/plugins/callback/osx_say.py index 476c66228a6..dd20c4bfac8 100644 --- a/lib/ansible/plugins/callback/osx_say.py +++ b/lib/ansible/plugins/callback/osx_say.py @@ -11,7 +11,7 @@ DOCUMENTATION = ''' type: notification requirements: - whitelising in configuration - - the '/usr/bin/say' command line program (standard on OS X) + - the '/usr/bin/say' command line program (standard on macOS) short_description: oneline Ansible screen output version_added: historical description: @@ -32,7 +32,7 @@ SAY_CMD = "/usr/bin/say" class CallbackModule(CallbackBase): """ - makes Ansible much more exciting on OS X. + makes Ansible much more exciting on macOS. """ CALLBACK_VERSION = 2.0 CALLBACK_TYPE = 'notification' diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index 5288b3bd8dc..a46f0aef615 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -275,7 +275,7 @@ def get_encrypted_password(password, hashtype='sha512', salt=None): if not HAS_PASSLIB: if sys.platform.startswith('darwin'): - raise AnsibleFilterError('|password_hash requires the passlib python module to generate password hashes on Mac OS X/Darwin') + raise AnsibleFilterError('|password_hash requires the passlib python module to generate password hashes on macOS/Darwin') saltstring = "$%s$%s" % (cryptmethod[hashtype], salt) encrypted = crypt.crypt(password, saltstring) else: diff --git a/test/integration/targets/tags/runme.sh b/test/integration/targets/tags/runme.sh index a8b1c90e1ae..311933902f4 100755 --- a/test/integration/targets/tags/runme.sh +++ b/test/integration/targets/tags/runme.sh @@ -2,7 +2,7 @@ set -eu -# Using set -x for this test causes the Shippable console to stop receiving updates and the job to time out for OS X. +# Using set -x for this test causes the Shippable console to stop receiving updates and the job to time out for macOS. # Once that issue is resolved the set -x option can be added above. # Run these using en_US.UTF-8 because list-tasks is a user output function and so it tailors its output to the diff --git a/test/runner/injector/injector.py b/test/runner/injector/injector.py index 31bc0cbc375..761a7c51ff8 100755 --- a/test/runner/injector/injector.py +++ b/test/runner/injector/injector.py @@ -120,7 +120,7 @@ def main(): try: cwd = os.getcwd() except OSError as ex: - # some platforms, such as OS X, may not allow querying the working directory when using become to drop privileges + # some platforms, such as macOS, may not allow querying the working directory when using become to drop privileges if ex.errno != errno.EACCES: raise if require_cwd: diff --git a/test/units/modules/network/f5/fixtures/load_ltm_irules.json b/test/units/modules/network/f5/fixtures/load_ltm_irules.json index b3e026a120b..05286e6b040 100644 --- a/test/units/modules/network/f5/fixtures/load_ltm_irules.json +++ b/test/units/modules/network/f5/fixtures/load_ltm_irules.json @@ -6,7 +6,7 @@ "fullPath": "/Common/_sys_APM_ExchangeSupport_OA_BasicAuth", "generation": 1, "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_OA_BasicAuth?ver=12.1.2", - "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond [ content ] [ * ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"Authentication FailuredError: Authentication Failure\"\n set static::actsync_503_http_body \"Service is not availableError: Service is not available\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as Mac OS X applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n }\n else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n set user_key \"$apm_username.$user_hash\"\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { ($f_release_request == 0) && ($retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE) } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection Close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature CZnUb3niz9wZPWvOmjDB0Dy4ixqjBEhIZrAVGt8VYe7+wZkhcBUFTADz3S1y5uomVwhRkGL20PLH7tfanDlpr3+IppgAGQlp98sPUl5ndEoWA4Rr90QiRGNRl/V7jWK58SOdJCQOirnutVMoeYjBWLwuprXGts08PO0WML5s0xJNOY7WPuGNeG+7Ht2pIB0vu80CgnCNGZJGZH0QR3kMVOx3yUN0ro5bAOmQ/XWel4qkj0F5DN9ufvsmKtTvb+Lc3y+5PHGbbFAQIrZ7lntZUJl/F8e/d26HE3spmZzQpPzi16qYWaMOxbvT6oedxpyhwbmJLiRNGyZmnT6kHj93FA==", + "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond [ content ] [ * ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"Authentication FailuredError: Authentication Failure\"\n set static::actsync_503_http_body \"Service is not availableError: Service is not available\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as macOS applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n }\n else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n set user_key \"$apm_username.$user_hash\"\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { ($f_release_request == 0) && ($retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE) } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection Close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature CZnUb3niz9wZPWvOmjDB0Dy4ixqjBEhIZrAVGt8VYe7+wZkhcBUFTADz3S1y5uomVwhRkGL20PLH7tfanDlpr3+IppgAGQlp98sPUl5ndEoWA4Rr90QiRGNRl/V7jWK58SOdJCQOirnutVMoeYjBWLwuprXGts08PO0WML5s0xJNOY7WPuGNeG+7Ht2pIB0vu80CgnCNGZJGZH0QR3kMVOx3yUN0ro5bAOmQ/XWel4qkj0F5DN9ufvsmKtTvb+Lc3y+5PHGbbFAQIrZ7lntZUJl/F8e/d26HE3spmZzQpPzi16qYWaMOxbvT6oedxpyhwbmJLiRNGyZmnT6kHj93FA==", "apiRawValues": { "verificationStatus": "signature-verified" } @@ -42,7 +42,7 @@ "fullPath": "/Common/_sys_APM_ExchangeSupport_main", "generation": 1, "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_main?ver=12.1.2", - "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond [ content ] [ * ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"Authentication FailuredError: Authentication Failure\"\n set static::actsync_503_http_body \"Service is not availableError: Service is not available\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as Mac OS X applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # Set it into 1 if the backend RPC-over-HTTP handler accepts HTTP Basic Authentication.\n set static::RPC_OVER_HTTP_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: RPC_OVER_HTTP_BKEND_BASIC_AUTH = $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH\"\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n if { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n if { $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH == 0 } {\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Use this virtual $static::ACCESS_SECOND_VIRTUAL_NAME just once. Will be reset back after disconnection.\"\n use virtual $static::ACCESS_SECOND_VIRTUAL_NAME\n }\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Remove HTTP Auth header\"\n HTTP::header remove Authorization\n }\n }\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set src_ip [IP::remote_addr]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [ string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n } else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n\n set user_key {}\n append user_key $apm_username \".\" $user_hash\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n # This is also going to touch the table entry timer.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { $f_release_request == 0 && $retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when HTTP_RESPONSE {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n set content_len [ HTTP::header Content-Length ]\n if { $content_len > 0 } {\n HTTP::collect $content_len\n }\n }\n }\n when HTTP_RESPONSE_DATA {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n if { [ regsub -line {Ntlm} [ HTTP::payload ] {Basic} payload ] != 0 } {\n HTTP::payload replace 0 $content_len $payload\n }\n }\n }\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature feX9LM+vB6YOEdVF+EA1JtNyVkPaB7gwdW0JzaB083MXl4yPP2nZnjm+WAx3YQhsmLttq5UkPl1zHpr5H9cwJX1bu9BNMi/+n0bIqWOipDHhhSYQ+TH+a5jQUSeftISr52BSQxh0cQKZkzM3rFU/qRZn9D9Dbf0kDGiDC1KWwVosrdjp5tVHOiQXWx8zybbGPFfgBcIBE6IvOvGbh5ohebVL2ADZm0URRj2NM4ZvZ2T3C14k2rHGXnDdRsvhmf5USZ+FH1hoKtWRxqtFjkWIaqw8leenXeot1j2bdKy92/AVTC9oZj1HJN1ePuQo5v414zlUhMEtkVy/gaxvj1+vPQ==", + "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond [ content ] [ * ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"Authentication FailuredError: Authentication Failure\"\n set static::actsync_503_http_body \"Service is not availableError: Service is not available\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as macOS applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # Set it into 1 if the backend RPC-over-HTTP handler accepts HTTP Basic Authentication.\n set static::RPC_OVER_HTTP_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: RPC_OVER_HTTP_BKEND_BASIC_AUTH = $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH\"\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n if { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n if { $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH == 0 } {\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Use this virtual $static::ACCESS_SECOND_VIRTUAL_NAME just once. Will be reset back after disconnection.\"\n use virtual $static::ACCESS_SECOND_VIRTUAL_NAME\n }\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Remove HTTP Auth header\"\n HTTP::header remove Authorization\n }\n }\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set src_ip [IP::remote_addr]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [ string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n } else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n\n set user_key {}\n append user_key $apm_username \".\" $user_hash\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n # This is also going to touch the table entry timer.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { $f_release_request == 0 && $retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when HTTP_RESPONSE {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n set content_len [ HTTP::header Content-Length ]\n if { $content_len > 0 } {\n HTTP::collect $content_len\n }\n }\n }\n when HTTP_RESPONSE_DATA {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n if { [ regsub -line {Ntlm} [ HTTP::payload ] {Basic} payload ] != 0 } {\n HTTP::payload replace 0 $content_len $payload\n }\n }\n }\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature feX9LM+vB6YOEdVF+EA1JtNyVkPaB7gwdW0JzaB083MXl4yPP2nZnjm+WAx3YQhsmLttq5UkPl1zHpr5H9cwJX1bu9BNMi/+n0bIqWOipDHhhSYQ+TH+a5jQUSeftISr52BSQxh0cQKZkzM3rFU/qRZn9D9Dbf0kDGiDC1KWwVosrdjp5tVHOiQXWx8zybbGPFfgBcIBE6IvOvGbh5ohebVL2ADZm0URRj2NM4ZvZ2T3C14k2rHGXnDdRsvhmf5USZ+FH1hoKtWRxqtFjkWIaqw8leenXeot1j2bdKy92/AVTC9oZj1HJN1ePuQo5v414zlUhMEtkVy/gaxvj1+vPQ==", "apiRawValues": { "verificationStatus": "signature-verified" }