Plugin Directory

Changeset 2513920


Ignore:
Timestamp:
04/13/2021 09:05:31 AM (5 years ago)
Author:
neosit
Message:

34d584d02db15e3e4dc492a799f01cf15db39cf2 Merge pull request #173 in ADI/next-active-directory-integration from develop to master

Location:
next-active-directory-integration/trunk
Files:
16 added
57 edited

Legend:

Unmodified
Added
Removed
  • next-active-directory-integration/trunk/Autoloader.php

    r1541870 r2513920  
    9999    private function isPluginClass($class)
    100100    {
    101         $prefixes = array('Adi', 'Core', 'Ldap', 'Multisite', 'Migration');
     101        $prefixes = array('Adi', 'Core', 'Ldap', 'Multisite', 'Migration', 'ActiveDirectory');
    102102
    103103        foreach ($prefixes as $prefix) {
  • next-active-directory-integration/trunk/classes/Adi/Authentication/Credentials.php

    r2029919 r2513920  
    11<?php
    2 if ( ! defined('ABSPATH')) {
     2if (!defined('ABSPATH')) {
    33    die('Access denied.');
    44}
     
    1212 * This class is mutable so parts of the credentials can be updated due to AD/LDAP lookups.
    1313 *
    14  * @author  Christopher Klein <ckl@neos-it.de>
     14 * @author  Christopher Klein <me[at]schakko[dot]de>
    1515 * @access public
    1616 */
     
    4646
    4747    /**
     48     * a specific Kerberos realm
     49     * @since 2.2.0
     50     * @var string
     51     */
     52    private $kerberosRealm;
     53
     54    /**
     55     * options for this context
     56     * @since 2.2.0
     57     * @var array
     58     */
     59    private $options = array();
     60
     61    /**
    4862     * NextADInt_Adi_Authentication_Credentials constructor.
    4963     *
    50      * @param string $login Login in form 'username' (sAMAccountName), 'username@domain' (userPrincipalName) or 'NETBIOS\sAMAccountName'
     64     * @param string $login Login in form 'username' (sAMAccountName), 'username@domain' (userPrincipalName) 'sAMAccountName@REALM' (Kerberors) or 'NETBIOS\sAMAccountName'
    5165     * @param string $password
    5266     */
     
    7589
    7690    /**
     91     * Add an additional option to the credential's context
     92     *
     93     * @param $key
     94     * @param $value
     95     * @since 2.2.0
     96     */
     97    public function setOption($key, $value)
     98    {
     99        $this->options[$key] = $value;
     100    }
     101
     102    /**
     103     * Return an option's value. it returns null if the option has not been set.
     104     *
     105     * @param $key
     106     * @return mixed|null
     107     * @since 2.2.0
     108     */
     109    public function getOption($key)
     110    {
     111        if (isset($this->options[$key])) {
     112            return $this->options[$key];
     113        }
     114
     115        return NULL;
     116    }
     117
     118    /**
    77119     * Get suffix without any '@' character
    78120     * @return string
     
    105147        $r = $this->upnUsername;
    106148
    107         if ( ! empty($this->upnSuffix)) {
     149        if (!empty($this->upnSuffix)) {
    108150            $r .= '@' . $this->upnSuffix;
    109151        }
     
    123165        if ($parts >= 2) {
    124166            $this->upnUsername = $parts[0];
    125             $this->upnSuffix   = $parts[1];
     167            $this->upnSuffix = $parts[1];
    126168        }
    127169    }
     
    228270    }
    229271
     272    /**
     273     * Get the user's Kerberos realm
     274     * @return string
     275     * @since 2.2.0
     276     */
     277    public function getKerberosRealm()
     278    {
     279        return $this->kerberosRealm;
     280    }
     281
     282    /**
     283     * Set the user's Kerberos realm
     284     * @param $kerberosRealm
     285     * @since 2.2.0
     286     */
     287    public function setKerberosRealm($kerberosRealm)
     288    {
     289        $this->kerberosRealm = $kerberosRealm;
     290    }
     291
     292    /**
     293     * Based upon this credential, a new LDAP query will be created
     294     *
     295     * @return NextADInt_Ldap_UserQuery|QueryForUser
     296     * @since 2.2.0
     297     */
     298    public function toUserQuery()
     299    {
     300        return NextADInt_Ldap_UserQuery::forPrincipal($this->login, $this);
     301    }
     302
    230303    public function __toString()
    231304    {
    232305        return "Credentials={login='" . $this->login . "',sAMAccountName='" . $this->sAMAccountName
    233                . "',userPrincipalName='" . $this->getUserPrincipalName() . "',netbios='" . $this->netbiosName
    234                . "',objectGuid='" . $this->objectGuid . "',wordPressUserId='" . $this->wordPressUserId . "'}";
     306            . "',userPrincipalName='" . $this->getUserPrincipalName() . "',netbios='" . $this->netbiosName
     307            . "',objectGuid='" . $this->objectGuid . "',wordPressUserId='" . $this->wordPressUserId
     308            . "',kerberosRealm='" . $this->kerberosRealm . "'}";
    235309    }
    236310}
  • next-active-directory-integration/trunk/classes/Adi/Authentication/LoginService.php

    r2224724 r2513920  
    4242    private $logger;
    4343
    44     /**
    45     * @var NextADInt_Adi_LoginState
    46     */
     44    /**
     45    * @var NextADInt_Adi_LoginState
     46    */
    4747    private $loginState;
    4848
     
    7171                                NextADInt_Adi_Authentication_Ui_ShowBlockedMessage $userBlockedMessage = null,
    7272                                NextADInt_Ldap_Attribute_Service $attributeService,
    73                                 NextADInt_Adi_LoginState $loginState,
     73                                NextADInt_Adi_LoginState $loginState,
    7474                                NextADInt_Adi_User_LoginSucceededService $loginSucceededService
    7575    )
     
    9393    public function register()
    9494    {
    95         // don't allow multiple registrations of the same LoginService instance
    96         if ($this->isRegistered) {
    97             return;
    98         }
     95        // don't allow multiple registrations of the same LoginService instance
     96        if ($this->isRegistered) {
     97            return;
     98        }
    9999
    100100        add_filter('authenticate', array($this, 'authenticate'), 10, 3);
     
    156156        // Check if this looks like a ProxyAddress and look up sAMAccountName if we are allowing ProxyAddresses as login.
    157157        $allowProxyAddressLogin = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::ALLOW_PROXYADDRESS_LOGIN);
    158         if($allowProxyAddressLogin && strpos($login, '@') !== false) {
     158        if ($allowProxyAddressLogin && strpos($login, '@') !== false) {
    159159            $login = $this->lookupFromProxyAddresses($login);
    160160        }
     
    168168        $password = stripslashes($password);
    169169
    170         $credentials = self::createCredentials($login, $password);
     170        $credentials = $this->buildCredentials($login, $password);
    171171        $suffixes = $this->detectAuthenticatableSuffixes($credentials->getUpnSuffix());
    172172
     
    208208     * @return The associated sAMAccountName or $proxyAddress if not found.
    209209     */
    210     public function lookupFromProxyAddresses($proxyAddress) {
     210    public function lookupFromProxyAddresses($proxyAddress)
     211    {
    211212
    212213        // Use the Sync to WordpPress username and password since anonymous bind can't search.
     
    221222        $domainControllerIsAvailable = $this->ldapConnection->checkPorts();
    222223
    223         if($domainControllerIsAvailable) {
     224        if ($domainControllerIsAvailable) {
    224225            $samaccountname = $this->ldapConnection->findByProxyAddress($proxyAddress);
    225226
    226227            // If this email address wasn't specified in anyone's proxyAddresses attributes, just return the original value.
    227             if($samaccountname === false) {
     228            if ($samaccountname === false) {
    228229                return $proxyAddress;
    229230            }
     
    266267                return $this->postAuthentication($credentials);
    267268            }
    268 
    269269        }
    270270
     
    275275
    276276    /**
    277      * Create a new instance of Adi_Authentication_ActiveDirectory
     277     * Create a new instance of NextADInt_Adi_Authentication_Credentials
    278278     *
    279279     * @param $login
     
    281281     *
    282282     * @return NextADInt_Adi_Authentication_Credentials
    283      */
    284     public static function createCredentials($login, $password)
    285     {
    286         return NextADInt_Adi_Authentication_PrincipalResolver::createCredentials($login, $password);
     283     * @since 2.0.0
     284     */
     285    public function buildCredentials($login, $password)
     286    {
     287        $r = NextADInt_Adi_Authentication_PrincipalResolver::createCredentials($login, $password);
     288
     289        /**
     290         * @var NextADInt_Adi_Authentication_Credentials
     291         */
     292        $r = apply_filters(NEXT_AD_INT_PREFIX . 'auth_configure_credentials', $r);
     293
     294        return $r;
    287295    }
    288296
     
    380388            $this->logger->debug("User domain '{$suffix}' is in list of account suffixes. Using this as first testable account suffix.");
    381389
    382             unset($arrAuthenticatableSuffixes[$idx]);
    383             array_unshift($arrAuthenticatableSuffixes, $suffix);
     390            // ADI-716: only return the user's suffix if it is inside the list of authenticatable suffixes
     391            return array($suffix);
    384392        }
    385393
     
    415423        // Otherwise, local authentication could still succeed and the counter would still be
    416424        // incremented
    417         if ($domainControllerIsAvailable){
     425        if ($domainControllerIsAvailable) {
    418426            // block or unblock user (depends on the authentication)
    419427            $this->refreshBruteForceProtectionStatusForUser($username, $accountSuffix, $success);
     
    441449     * @param $accountSuffix
    442450     * @internal param string $fullUsername
    443     * @deprecated 1.0.13 use external plugin for brute force protection
    444     * @see https://wordpress.org/plugins/better-wp-security/
     451    * @deprecated 1.0.13 use external plugin for brute force protection
     452    * @see https://wordpress.org/plugins/better-wp-security/
    445453     */
    446454    function bruteForceProtection($username, $accountSuffix)
     
    496504     * @param boolean $successfulLogin if true, the user is un-blocked; otherwise, he is blocked
    497505     * @internal param string $fullUsername
    498     * @deprecated 1.0.13 use external plugin for brute force protection
    499     * @see https://wordpress.org/plugins/better-wp-security/
     506    * @deprecated 1.0.13 use external plugin for brute force protection
     507    * @see https://wordpress.org/plugins/better-wp-security/
    500508     */
    501509    function refreshBruteForceProtectionStatusForUser($username, $accountSuffix, $successfulLogin)
     
    514522        if ($successfulLogin) {
    515523            $this->failedLogin->deleteLoginAttempts($fullUsername);
    516         }
    517         // ADI-705: check for existing variable and *not* null; findByActiveDirectoryUsername returns false
     524        } // ADI-705: check for existing variable and *not* null; findByActiveDirectoryUsername returns false
    518525        elseif ($wpUser && $this->userManager->isNadiUser($wpUser)) {
    519526            $this->failedLogin->increaseLoginAttempts($fullUsername);
     
    538545
    539546        // ADI-204: during login we have to use the authenticated user principal name
    540         $ldapAttributes = $this->attributeService->findLdapAttributesOfUser($credentials, null);
     547        $ldapAttributes = $this->attributeService->resolveLdapAttributes($credentials->toUserQuery());
    541548
    542549        // ADI-395: wrong base DN leads to exception during Test Authentication
     
    548555
    549556        // update the real sAMAccountName of the credentials. This could be totally different from the userPrincipalName user for login
     557        $this->updateCredentials($credentials, $ldapAttributes);
     558
     559        // state: user is authenticated
     560        $this->loginState->setAuthenticationSucceeded();
     561
     562        return $credentials;
     563    }
     564
     565    /**
     566     * Update the credential data (sAMAccountName, userPrincipalName, objectGUID) based upon the filtered LDAP attributes
     567     *
     568     * @param NextADInt_Adi_Authentication_Credentials $credentials
     569     * @param NextADInt_Ldap_Attributes $ldapAttributes
     570     * @pack
     571     * @since 2.0.0
     572     */
     573    function updateCredentials(NextADInt_Adi_Authentication_Credentials $credentials, NextADInt_Ldap_Attributes $ldapAttributes)
     574    {
    550575        $credentials->setSAMAccountName($ldapAttributes->getFilteredValue('samaccountname'));
    551576        $credentials->setObjectGuid($ldapAttributes->getFilteredValue('objectguid'));
    552 
    553         // state: user is authenticated
    554         $this->loginState->setAuthenticationSucceeded();
    555 
    556         return $credentials;
     577        $credentials->setUserPrincipalName($ldapAttributes->getFilteredValue('userprincipalname'));
    557578    }
    558579
  • next-active-directory-integration/trunk/classes/Adi/Authentication/SingleSignOn/Service.php

    r2069979 r2513920  
    1717class NextADInt_Adi_Authentication_SingleSignOn_Service extends NextADInt_Adi_Authentication_LoginService
    1818{
    19     /**
    20      * If Kerberos or certificate authentication failed
    21      */
    22     const FAILED_SSO_UPN = 'failedSsoUpn';
    23 
    24     /**
    25      * If NTLM authentication failed
    26      */
    27     const FAILED_SSO_NETBIOS_NAME = 'failedSsoNetbios';
     19    const FAILED_SSO_PRINCIPAL = "failedSsoPrincipal";
    2820
    2921    const USER_LOGGED_OUT = 'userLoggedOut';
     
    3729    /** @var NextADInt_Adi_User_LoginSucceededService $loginSucceededService */
    3830    private $loginSucceededService;
     31
     32    /**
     33     * @since 2.0.0
     34     * @var NextADInt_Adi_Authentication_SingleSignOn_Profile_Locator
     35     */
     36    private $ssoProfileLocator;
    3937
    4038    public function __construct(NextADInt_Adi_Authentication_Persistence_FailedLoginRepository $failedLogin = null,
     
    4644                                NextADInt_Ldap_Attribute_Service $attributeService,
    4745                                NextADInt_Adi_Authentication_SingleSignOn_Validator $validation,
    48                                 NextADInt_Adi_LoginState $loginState,
    49                                 NextADInt_Adi_User_LoginSucceededService $loginSucceededService
     46                                NextADInt_Adi_LoginState $loginState,
     47                                NextADInt_Adi_User_LoginSucceededService $loginSucceededService,
     48                                NextADInt_Adi_Authentication_SingleSignOn_Profile_Locator $ssoProfileLocator
    5049    )
    5150    {
     
    5655        $this->logger = NextADInt_Core_Logger::getLogger();
    5756        $this->loginSucceededService = $loginSucceededService;
     57        $this->ssoProfileLocator = $ssoProfileLocator;
    5858    }
    5959
     
    7777    }
    7878
    79     /**
    80     * Check if the user can be authenticated using user from the client machine.
    81     *
    82     * @param null $user
    83     * @param string $login
    84     * @param string $password
    85     *
    86     * @return bool
    87     * @throws Exception
    88     */
     79    /**
     80    * Check if the user can be authenticated using user from the client machine.
     81    *
     82    * @param null $user
     83    * @param string $login
     84    * @param string $password
     85    *
     86    * @return bool
     87    * @throws Exception
     88    */
    8989    public function authenticate($user = null /* required for WordPress callback */, $login = '', $password = '')
    9090    {
     
    105105        }
    106106
    107         $credentials = self::createCredentials($username, '');
     107        $credentials = $this->buildCredentials($username, '');
    108108        $sessionHandler = $this->getSessionHandler();
    109109
     
    122122            $validation->validateAuthenticationState($credentials);
    123123
    124             $netbiosName = $credentials->getNetbiosName();
    125 
    126             if (isset($netbiosName)) {
    127                 $credentials = $this->ntlmAuth($credentials, $validation);
    128             } else {
    129                 // $username or $username@$upnSuffix
    130                 $credentials = $this->kerberosAuth($credentials, $validation);
    131             }
     124            // encapsulate the authentication process
     125            $credentials = $this->delegateAuth($credentials, $validation);
    132126
    133127            // authenticate the given user and run the default procedure form the LoginService
    134128            $authenticatedCredentials = $this->parentAuthenticate($credentials);
    135             if(!$authenticatedCredentials) {
    136                 throw new NextADInt_Adi_Authentication_Exception("Unable to authenticate user" . $credentials->getUserPrincipalName());
     129
     130            if (!$authenticatedCredentials) {
     131                throw new NextADInt_Adi_Authentication_Exception("Unable to authenticate user " . $credentials->getUserPrincipalName());
    137132            }
    138 
    139133
    140134            // as SSO runs during the "init" phase, we need to call the 'authorize' filter on our own
     
    143137
    144138            // if our user is authenticated and we have a WordPress user, we
    145             $sessionHandler->clearValue(self::FAILED_SSO_UPN);
     139            $sessionHandler->clearValue(self::FAILED_SSO_PRINCIPAL);
    146140        } catch (NextADInt_Adi_Authentication_Exception $e) {
    147141            $this->logger->error('User could not be authenticated using SSO. ' . $e->getMessage());
    148             $sessionHandler->setValue(self::FAILED_SSO_UPN, $credentials->getUserPrincipalName());
     142            $sessionHandler->setValue(self::FAILED_SSO_PRINCIPAL, $credentials->getLogin());
    149143
    150144            return false;
     
    152146
    153147        return true;
     148    }
     149
     150    /**
     151     * Execute the authentication by looking up the username (sAMAccountName, userPrincipalName or Kerberos principal) inside the Active Directory.
     152     *
     153     * @param NextADInt_Adi_Authentication_Credentials $credentials
     154     * @param $validation
     155     * @return NextADInt_Adi_Authentication_Credentials
     156     * @throws NextADInt_Adi_Authentication_Exception
     157     * @since 2.2.0
     158     */
     159    function delegateAuth(NextADInt_Adi_Authentication_Credentials $credentials, $validation)
     160    {
     161        // let our locator find a matching profile, based upon the given credentials
     162        $profileMatch = $this->ssoProfileLocator->locate($credentials);
     163
     164        // a valid profile is required for login
     165        $validation->validateProfile($profileMatch->getProfile());
     166
     167        $this->logger->debug("Valid SSO profile for type '" . $profileMatch->getType() . "' found");
     168        // fire a hook to inform that one of the SSO profiles has been matched
     169        do_action(NEXT_AD_INT_PREFIX . 'sso_profile_located', $credentials, $profileMatch);
     170
     171        $this->openLdapConnection($profileMatch->getProfile());
     172
     173        $ldapAttributes = $this->getAttributeService()->resolveLdapAttributes($credentials->toUserQuery());
     174
     175        if ($ldapAttributes->getRaw() == false) {
     176            throw new NextADInt_Adi_Authentication_Exception("User '" . $credentials->getLogin() . "' does not exist in Active Directory'");
     177        }
     178
     179        // update the user's credentials, so we have valid a userPrincipalName, GUID and sAMAccountName based upon recent Active Directory data
     180        $this->updateCredentials($credentials, $ldapAttributes);
     181
     182        return $credentials;
    154183    }
    155184
     
    168197
    169198    /**
    170      * Create new credentials based upon sAMAccountName or userPrincipalName
    171      *
    172      * @throws NextADInt_Adi_Authentication_Exception If the user's attribute could not be found
    173      * @param NextADInt_Adi_Authentication_Credentials $credentials
    174      * @return NextADInt_Adi_Authentication_Credentials
    175      */
    176     function createUpnCredentials(NextADInt_Adi_Authentication_Credentials $credentials)
    177     {
    178         // findLdapAttributesOfUser tries both sAMAccountName and userPrincipalName
    179         $ldapAttributes = $this->getAttributeService()->findLdapAttributesOfUser($credentials, '');
    180 
    181         if ($ldapAttributes->getRaw() == false) {
    182             throw new NextADInt_Adi_Authentication_Exception("User '" . $credentials->getLogin() . "' does not exist in Active Directory'");
    183         }
    184 
    185         $upn = $ldapAttributes->getFilteredValue('userprincipalname');
    186         $samaccountname = $ldapAttributes->getFilteredValue('samaccountname');
    187         $credentials = self::createCredentials($upn, '');
    188         // ADI-620: make sure that the sAMAccountName is explicitly set as it does not have to correlate with the userPrincipalName
    189         $credentials->setSAMAccountName($samaccountname);
    190 
    191         return $credentials;
    192     }
    193 
    194     /**
    195      * Authenticate given credentials by using an internal lookup of the provided NETBIOS name.
    196      *
    197      * @throws NextADInt_Adi_Authentication_Exception if the profile could not be found
    198      * @param NextADInt_Adi_Authentication_Credentials $credentials
    199      * @param NextADInt_Adi_Authentication_SingleSignOn_Validator $validation
    200      * @return NextADInt_Adi_Authentication_Credentials
    201      */
    202     function ntlmAuth(NextADInt_Adi_Authentication_Credentials $credentials, NextADInt_Adi_Authentication_SingleSignOn_Validator $validation)
    203     {
    204         $this->logger->info('SSO authentication triggered using NTLM for user ' . $credentials->getLogin());
    205         $profile = null;
    206 
    207         // find assigned profile by previously detected nETBIOSName
    208         try {
    209             $profile = $this->findBestConfigurationMatchForProfile(NextADInt_Adi_Configuration_Options::NETBIOS_NAME, $credentials->getNetbiosName());
    210 
    211             $validation->validateProfile($profile);
    212         } catch (NextADInt_Adi_Authentication_Exception $e) {
    213             $this->logger->error("Validation of profile for NETBIOS name '" . $credentials->getNetbiosName() . "' failed: " . $e->getMessage());
    214 
    215             throw new NextADInt_Adi_Authentication_Exception("Unable to find matching NADI profile for NETBIOS name '" . $credentials->getNetbiosName() . "'. Is NADI connected to a valid Active Directory domain?");
    216         }
    217 
    218         $this->openLdapConnection($profile);
    219 
    220         // create required credentials with userPrincipalName and upnSuffix. At the moment we got only nETBIOSName and sAMAccountName
    221         $credentials = $this->createUpnCredentials($credentials);
    222 
    223         return $credentials;
    224     }
    225 
    226     /**
    227      * Authenticate given credentials by using an internal lookup of the provided UPN suffix.
    228      *
    229      * @param NextADInt_Adi_Authentication_Credentials $credentials
    230      * @param NextADInt_Adi_Authentication_SingleSignOn_Validator $validation
    231      *
    232      * @return NextADInt_Adi_Authentication_Credentials
    233      * @throws NextADInt_Adi_Authentication_Exception
    234      */
    235     function kerberosAuth(NextADInt_Adi_Authentication_Credentials $credentials, NextADInt_Adi_Authentication_SingleSignOn_Validator $validation)
    236     {
    237         $this->logger->info('SSO authentication triggered using Kerberos for user ' . $credentials->getLogin());
    238 
    239         // normalize our suffix, to prevent inconsistencies
    240         $suffix = $this->normalizeSuffix($credentials->getUpnSuffix());
    241 
    242         // get the profile and check if it is valid
    243         $profile = $this->findBestConfigurationMatchForProfile(NextADInt_Adi_Configuration_Options::ACCOUNT_SUFFIX, $suffix);
    244         $validation->validateProfile($profile);
    245         $this->openLdapConnection($profile);
    246 
    247         // try to resolve the user using the sAMAccountName, if no suffix has been found
    248         if (null === $credentials->getUpnSuffix()) {
    249             $credentials = $this->createUpnCredentials($credentials);
    250         }
    251 
    252         return $credentials;
    253     }
    254 
    255     /**
    256199     * Clear the session values for failed sso or manual logout if the user wants to retry authentication over SSO.
    257200     */
     
    259202    {
    260203        if ('sso' === NextADInt_Core_Util_ArrayUtil::get('reauth', $_GET, false)) {
    261             $this->getSessionHandler()->clearValue(self::FAILED_SSO_UPN);
     204            $this->getSessionHandler()->clearValue(self::FAILED_SSO_PRINCIPAL);
    262205            $this->getSessionHandler()->clearValue(self::USER_LOGGED_OUT);
    263206        }
     
    296239
    297240        $this->validation->validateLdapConnection($this->getLdapConnection());
    298     }
    299 
    300     /**
    301      * Get account suffix for given credentials
    302      *
    303      * @param string $suffix
    304      *
    305      * @return array
    306      */
    307     public function detectAuthenticatableSuffixes($suffix)
    308     {
    309         $profile = $this->findBestConfigurationMatchForProfile(NextADInt_Adi_Configuration_Options::ACCOUNT_SUFFIX, $suffix);
    310 
    311         if (null === $profile) {
    312             return array($suffix);
    313         }
    314 
    315         return NextADInt_Core_Util_StringUtil::split($profile[NextADInt_Adi_Configuration_Options::ACCOUNT_SUFFIX], ';');
    316     }
    317 
    318     /**
    319      * Find the profile with SSO enabled and its configuration option contains the provided value.
    320      *
    321      * @param $option name of profile option
    322      * @param $value value of given option to match
    323      *
    324      * @return mixed
    325      */
    326     public function findBestConfigurationMatchForProfile($option, $value)
    327     {
    328         $ssoEnabledProfiles = $this->findSsoEnabledProfiles();
    329 
    330         // find all profiles with given option value
    331         $profiles = $this->getProfilesWithOptionValue($option, $value, $ssoEnabledProfiles);
    332 
    333         // if multiple profiles were found, log a warning and return the first result
    334         if (sizeof($profiles) > 1) {
    335             $this->logger->warn('Multiple profiles with the same option "' . $option . '" and enabled SSO were found.');
    336         }
    337 
    338         // if no profile given suffix and sso enabled was found, search for profiles with SSO enabled and no suffixes
    339         if (sizeof($profiles) == 0) {
    340             $profiles = $this->getProfilesWithoutOptionValue($option, $ssoEnabledProfiles);
    341         }
    342 
    343         // return the first found profile or null
    344         return NextADInt_Core_Util_ArrayUtil::findFirstOrDefault($profiles, null);
    345     }
    346 
    347     /**
    348      * Get all profiles with the given option value.
    349      *
    350      * @param $option name of configuration option to search for
    351      * @param $requiredValue
    352      * @param $profiles
    353      *
    354      * @return array
    355      */
    356     protected function getProfilesWithOptionValue($option, $requiredValue, $profiles)
    357     {
    358         return NextADInt_Core_Util_ArrayUtil::filter(function ($profile) use ($option, $requiredValue) {
    359             $values = array();
    360 
    361             if (isset($profile[$option])) {
    362                 $values = NextADInt_Core_Util_StringUtil::split($profile[$option], ';');
    363             }
    364 
    365             return (NextADInt_Core_Util_ArrayUtil::containsIgnoreCase($requiredValue, $values));
    366         }, $profiles);
    367     }
    368 
    369     /**
    370      * Get all profiles which have no option specified.
    371      *
    372      * @param $option name of configuration option
    373      * @param $profiles
    374      *
    375      * @return array
    376      */
    377     protected function getProfilesWithoutOptionValue($option, $profiles)
    378     {
    379         return NextADInt_Core_Util_ArrayUtil::filter(function ($profile) use ($option) {
    380             $value = '';
    381 
    382             if (isset($profile[$option])) {
    383                 $value = $profile[$option];
    384             }
    385 
    386             return NextADInt_Core_Util_StringUtil::isEmptyOrWhitespace($value);
    387         }, $profiles);
    388241    }
    389242
     
    394247     * find a problem with this solution.
    395248     *
    396      * @param string $username
    397      * @param null|string $accountSuffix
    398      * @param string $password
    399      *
    400      * @return bool
    401      */
    402     public function authenticateAtActiveDirectory($username, $accountSuffix, $password)
    403     {
    404         return true;
     249     * @param NextADInt_Adi_Authentication_Credentials $credentials
     250     * @param array $suffixes
     251     * @return bool|NextADInt_Adi_Authentication_Credentials
     252     * @throws Exception
     253     * @since 2.0.0
     254     */
     255    public function tryAuthenticatableSuffixes(NextADInt_Adi_Authentication_Credentials $credentials, $suffixes = array())
     256    {
     257        $this->logger->info("User has been authenticated through SSO, running post authentication");
     258        return $this->postAuthentication($credentials);
     259    }
     260
     261    /**
     262     * It returns the suffix itself as we have been already authenticated previously
     263     *
     264     * @param string $suffix
     265     * @return array
     266     */
     267    public function detectAuthenticatableSuffixes($suffix)
     268    {
     269        // there is no more logic required; we just want to make sure that the parent's tryAuthenticatableSuffixes method call is executed
     270        $this->logger->info("Authenticatable suffixes are ignored");
     271        return array($suffix);
    405272    }
    406273
     
    424291
    425292        return $connection;
    426     }
    427 
    428     /**
    429      * Return the suffix with an '@' prefix.
    430      *
    431      * @param $suffix
    432      *
    433      * @return string
    434      */
    435     protected function normalizeSuffix($suffix)
    436     {
    437         if (!empty($suffix) && '@' !== $suffix[0]) {
    438             $suffix = '@' . $suffix;
    439         }
    440 
    441         return $suffix;
    442     }
    443 
    444     /**
    445      * Find all profiles with the necessary roles.
    446      *
    447      * @return array
    448      */
    449     protected function findSsoEnabledProfiles()
    450     {
    451         // find all profiles with the given options and add them to our $profiles array
    452         $profiles = $this->getConfiguration()->findAllProfiles(array(
    453             NextADInt_Adi_Configuration_Options::ACCOUNT_SUFFIX,
    454             NextADInt_Adi_Configuration_Options::SSO_ENABLED,
    455             NextADInt_Adi_Configuration_Options::SSO_USER,
    456             NextADInt_Adi_Configuration_Options::SSO_PASSWORD,
    457             NextADInt_Adi_Configuration_Options::DOMAIN_CONTROLLERS,
    458             NextADInt_Adi_Configuration_Options::PORT,
    459             NextADInt_Adi_Configuration_Options::ENCRYPTION,
    460             NextADInt_Adi_Configuration_Options::NETWORK_TIMEOUT,
    461             NextADInt_Adi_Configuration_Options::BASE_DN,
    462             NextADInt_Adi_Configuration_Options::SSO_USER,
    463             NextADInt_Adi_Configuration_Options::SSO_PASSWORD,
    464             NextADInt_Adi_Configuration_Options::NETBIOS_NAME
    465         ));
    466 
    467         // get the current configuration and add it as first option
    468         // this is required in a single site environment, as the profile will not be listed above
    469         array_unshift($profiles, $this->getConfiguration()->getAllOptions());
    470 
    471         // filter all profiles and get profiles with SSO enabled
    472         $profiles = NextADInt_Core_Util_ArrayUtil::filter(function ($profile) {
    473             if (!isset($profile[NextADInt_Adi_Configuration_Options::SSO_ENABLED]['option_value'])) {
    474                 return false;
    475             }
    476 
    477             return $profile[NextADInt_Adi_Configuration_Options::SSO_ENABLED]['option_value'] === true;
    478         }, $profiles);
    479 
    480         return $this->normalizeProfiles($profiles);
    481     }
    482 
    483     /**
    484      * Normalize the given profiles for further usage.
    485      *
    486      * @param $profiles
    487      *
    488      * @return array
    489      */
    490     protected function normalizeProfiles($profiles)
    491     {
    492         // go through all found profiles and normalize the values
    493         return NextADInt_Core_Util_ArrayUtil::map(function ($profile) {
    494             // set the option_value as the real value
    495             return NextADInt_Core_Util_ArrayUtil::map(function ($profileOption) {
    496                 return $profileOption['option_value'];
    497             }, $profile);
    498         }, $profiles);
    499293    }
    500294
  • next-active-directory-integration/trunk/classes/Adi/Authentication/SingleSignOn/Validator.php

    r2029919 r2513920  
    1818class NextADInt_Adi_Authentication_SingleSignOn_Validator
    1919{
    20     const FAILED_SSO_UPN = NextADInt_Adi_Authentication_SingleSignOn_Service::FAILED_SSO_UPN;
    21 
    22     const USER_LOGGED_OUT = NextADInt_Adi_Authentication_SingleSignOn_Service::USER_LOGGED_OUT;
    23 
    2420    /**
    2521     * Check if the given {@link NextADInt_Ldap_Connection} is connected.
     
    7369    public function validateAuthenticationState(NextADInt_Adi_Authentication_Credentials $credentials)
    7470    {
    75         $failedAuthenticateUsername = $this->getSessionHandler()->getValue(self::FAILED_SSO_UPN);
     71        $failedAuthenticateUsername = $this->getSessionHandler()->getValue(NextADInt_Adi_Authentication_SingleSignOn_Service::FAILED_SSO_PRINCIPAL);
    7672
    77         if ($failedAuthenticateUsername === $credentials->getUserPrincipalName()) {
     73        if (!empty($failedAuthenticateUsername) && ($failedAuthenticateUsername === $credentials->getLogin())) {
    7874            $this->throwAuthenticationException('User has already failed to authenticate. Stop retrying.');
    7975        }
     
    8783    public function validateLogoutState()
    8884    {
    89         $userLoggedOut = $this->getSessionHandler()->getValue(self::USER_LOGGED_OUT, false);
     85        $userLoggedOut = $this->getSessionHandler()->getValue(NextADInt_Adi_Authentication_SingleSignOn_Service::USER_LOGGED_OUT, false);
    9086
    9187        if ($userLoggedOut) {
  • next-active-directory-integration/trunk/classes/Adi/Authentication/VerificationService.php

    r2331595 r2513920  
    4141     * @param array $data
    4242     *
    43      * @return bool false || string $objectId
     43     * @return bool|ActiveDirectory_Sid
    4444     */
    4545    public function findActiveDirectoryDomainSid($data)
  • next-active-directory-integration/trunk/classes/Adi/Configuration/Options.php

    r2331595 r2513920  
    3636    const DOMAIN_SID = 'domain_sid';
    3737    const NETBIOS_NAME = 'netbios_name';
     38    const ADDITIONAL_DOMAIN_SIDS = 'additional_domain_sids';
     39
     40    // Forest
     41    const KERBEROS_REALM_MAPPINGS = 'kerberos_realm_mappings';
    3842
    3943    // User - User Settings
     
    508512                $transient => false,
    509513            ),
    510 
    511514            self::NETBIOS_NAME => array(
    512515                $title => __('NetBIOS name', 'next-active-directory-integration'),
     
    524527                $default => '',
    525528                $sanitizer => array('string'),
     529                $showPermission => true,
     530                $transient => false,
     531            ),
     532            // additional domain SIDs when using a Global Catalog
     533            self::ADDITIONAL_DOMAIN_SIDS => array(
     534                $title => __('Additional domain SIDs', 'next-active-directory-integration'),
     535                $type => NextADInt_Multisite_Option_Type::EDITABLE_LIST,
     536                $description => __(
     537                    'Recognize users during import from these domain SIDs. The specified SIDs are used in <strong>addition</strong> to the already connected domain above.',
     538                    'next-active-directory-integration'
     539                ),
     540                $detail => array(
     541                    __(
     542                        'When using a <em>Global Catalog</em> handling more than one domain, you have to specify each additional domain inside it',
     543                        'next-active-directory-integration'
     544                    ),
     545                ),
     546                $angularAttributes => '',
     547                $angularButtonAttributes => 'ng-show="!$parent.is_input_empty(new_additional_domain_sids)"',
     548                $default => '',
     549                $sanitizer => array('accumulation', ';', array('string', false, true)),
    526550                $showPermission => true,
    527551                $transient => false,
     
    11171141                $transient => false,
    11181142            ),
    1119             // Allows users who usually require a smart card to log in using NADI
     1143            // Kerberos realm mappings
     1144            self::KERBEROS_REALM_MAPPINGS => array(
     1145                $title => __('Kerberos realm mappings', 'next-active-directory-integration'),
     1146                $type => NextADInt_Multisite_Option_Type::TEXTAREA,
     1147                $description => __(
     1148                    'Specify all Kerberos realms and their designated UPN suffixes',
     1149                    'next-active-directory-integration'
     1150                ),
     1151                $detail => array(
     1152                    __(
     1153                        'This is only required if you are inside an Active Directory forest with a Global Catalog and Kerberos enabled. You need the <em>Multi-domain Forest Premium Extension</em>em>',
     1154                        'next-active-directory-integration'
     1155                    ),
     1156                    __('Example:', 'next-active-directory-integration'),
     1157                    __('FIRSTKRBREALM.COM=upnsuffix1.com;', 'next-active-directory-integration'),
     1158                    __('SECONDKRBREALM.COM=upnsuffix2.de,upnsuffix3.org;', 'next-active-directory-integration'),
     1159                    __(
     1160                        'Please take a look at our documentation at <a href="https://active-directory-wp.com/docs/Configuration/Sso" target="__blank">https://active-directory-wp.com/docs/Configuration/Sso</a>',
     1161                        'next-active-directory-integration'
     1162                    ),
     1163                ),
     1164                $angularAttributes => 'ng-disabled="((!option.sso) || ((permission.sso == 2) || (permission.sso == 1))',
     1165                $default => '',
     1166                $showPermission => true,
     1167                $transient => false,
     1168            ),
     1169            // Allows users who usually require a smart card to log in using NADI
    11201170            self::ENABLE_SMARTCARD_USER_LOGIN => array(
    11211171                $title => __('Enable login for smart card Users', 'next-active-directory-integration'),
  • next-active-directory-integration/trunk/classes/Adi/Configuration/Ui/Layout.php

    r2331595 r2513920  
    8585                ),
    8686            ),
    87             // Tab name
     87            // Environment tab
    8888            __('Environment', 'next-active-directory-integration') => array(
    8989                // Group Name
     
    117117                    )
    118118                ),
    119             ),
    120             // Tab name
     119                __('Forest configuration', 'next-active-directory-integration') => array(
     120                    self::DESCRIPTION => __(
     121                        'This is only relevant if you are using NADI inside an AD forest. You need the premium extension <a href="https://active-directory-wp.com/premium-extension/active-directory-forest/" target="__blank">Active Directory Forest</a> to have any effect for the forest configuration.',
     122                        'next-active-directory-integration'
     123                    ),
     124                    self::OPTIONS => array(
     125                        NextADInt_Adi_Configuration_Options::ADDITIONAL_DOMAIN_SIDS,
     126                    )
     127                )
     128            ),
     129            // User tab
    121130            __('User', 'next-active-directory-integration') => array(
    122131                // Group Name
     
    145154                ),
    146155            ),
    147             // Tab name
     156            // Password tab
    148157            __('Password', 'next-active-directory-integration') => array(
    149158                self::ANGULAR_CONTROLLER => 'PasswordController',
     
    165174                ),
    166175            ),
    167             // Tab name
     176            // Permissions tab
    168177            __('Permissions', 'next-active-directory-integration') => array(
    169178                self::ANGULAR_CONTROLLER => 'PermissionController',
     
    189198                ),
    190199            ),
    191             // Tab name
    192             __('Security', 'next-active-directory-integration') => array(
    193                 self::ANGULAR_CONTROLLER => 'SecurityController',
     200            // SSO tab
     201            __('SSO', 'next-active-directory-integration') => array(
     202                self::ANGULAR_CONTROLLER => 'SsoController',
    194203                self::MULTISITE_ONLY => false,
    195204                // Group name
     
    200209                    ),
    201210                        __(
    202                             '<span class="adi-pe-message"><b>Premium Extensions: </b>SingleSignOn for BuddyPress, WooCommerce und Ultimate Member <a href="https://active-directory-wp.com/premium-extension/">available</a>.</span>',
     211                            '<span class="adi-pe-message"><b>Premium Extensions: </b>Active Directory Forest, SingleSignOn for BuddyPress, WooCommerce und Ultimate Member <a href="https://active-directory-wp.com/premium-extension/">available</a>.</span>',
    203212                            'next-active-directory-integration'
    204213                        )),
     
    209218                        NextADInt_Adi_Configuration_Options::SSO_PASSWORD,
    210219                        NextADInt_Adi_Configuration_Options::SSO_ENVIRONMENT_VARIABLE,
    211                         NextADInt_Adi_Configuration_Options::SSO_DISABLE_FOR_XMLRPC
    212                     ),
    213                 ),
     220                        NextADInt_Adi_Configuration_Options::SSO_DISABLE_FOR_XMLRPC,
     221                        NextADInt_Adi_Configuration_Options::KERBEROS_REALM_MAPPINGS,
     222                    ),
     223                ),
     224            ),
     225            // Security tab
     226            __('Security', 'next-active-directory-integration') => array(
     227                self::ANGULAR_CONTROLLER => 'SecurityController',
     228                self::MULTISITE_ONLY => false,
    214229                // Group name
    215230                __('Login', 'next-active-directory-integration') => array(
     
    249264                ),
    250265            ),
    251             // Tab name
     266            // Attributes tab
    252267            __('Attributes', 'next-active-directory-integration') => array(
    253268                self::ANGULAR_CONTROLLER => 'AttributesController',
     
    278293                ),
    279294            ),
    280             // Tab name
     295            // Sync to AD tab
    281296            __('Sync to AD', 'next-active-directory-integration') => array(
    282297                self::ANGULAR_CONTROLLER => 'SyncToAdController',
     
    298313                ),
    299314            ),
    300             // Tab name
     315            // Sync to WordPress tab
    301316            __('Sync to WordPress', 'next-active-directory-integration') => array(
    302317                self::ANGULAR_CONTROLLER => 'SyncToWordpressController',
     
    321336                ),
    322337            ),
    323             // Tab name
     338            // Logging tab
    324339            __('Logging', 'next-active-directory-integration') => array(
    325340                self::ANGULAR_CONTROLLER => 'LoggingController',
  • next-active-directory-integration/trunk/classes/Adi/Dependencies.php

    r2069979 r2513920  
    2727     * @return NextADInt_Adi_Dependencies
    2828     */
    29     public static function getInstance() {
     29    public static function getInstance()
     30    {
    3031        if (self::$_instance === null) {
    3132            self::$_instance = new NextADInt_Adi_Dependencies();
     
    316317        if ($this->ldapConnection == null) {
    317318            $this->ldapConnection = new NextADInt_Ldap_Connection(
    318                 $this->getConfiguration()
    319             );
     319                $this->getConfiguration(),
     320                $this->getActiveDirectoryContext()
     321            );
     322
     323            $this->ldapConnection->register();
    320324        }
    321325
     
    509513                $this->getShowBlockedMessage(),
    510514                $this->getAttributeService(),
    511                 $this->getLoginState(),
     515                $this->getLoginState(),
    512516                $this->getLoginSucceededService()
    513517            );
     
    11061110                $this->getAttributeService(),
    11071111                $this->getSsoValidator(),
    1108                 $this->getLoginState(),
    1109                 $this->getLoginSucceededService()
     1112                $this->getLoginState(),
     1113                $this->getLoginSucceededService(),
     1114                $this->getSsoProfileLocator()
    11101115            );
    11111116        }
     
    11251130    {
    11261131        if ($this->ssoPage == null) {
    1127             // TODO SSO Error wp-login
     1132            // TODO SSO Error wp-login
    11281133            $this->ssoPage = new NextADInt_Adi_Authentication_Ui_SingleSignOn();
    11291134        }
     
    11491154    }
    11501155
    1151     /**
    1152     * @var NextADInt_Adi_LoginState
    1153     */
     1156    /**
     1157    * @var NextADInt_Adi_LoginState
     1158    */
    11541159    private $loginState = null;
    11551160
    1156     /**
    1157      * @return NextADInt_Adi_LoginState
    1158      */
    1159     public function getLoginState() {
    1160         if ($this->loginState == null) {
    1161             $this->loginState = new NextADInt_Adi_LoginState();
    1162         }
    1163 
    1164         return $this->loginState;
    1165     }
    1166 
    1167     /**
    1168      * @var NextADInt_Adi_Authorization_Service
    1169      */
     1161    /**
     1162     * @return NextADInt_Adi_LoginState
     1163     */
     1164    public function getLoginState()
     1165    {
     1166        if ($this->loginState == null) {
     1167            $this->loginState = new NextADInt_Adi_LoginState();
     1168        }
     1169
     1170        return $this->loginState;
     1171    }
     1172
     1173    /**
     1174     * @var NextADInt_Adi_Authorization_Service
     1175     */
    11701176    private $authorizationService = null;
    11711177
    1172     /**
    1173      * @return NextADInt_Adi_Authorization_Service
    1174      */
    1175     public function getAuthorizationService() {
    1176         if ($this->authorizationService == null) {
    1177             $this->authorizationService = new NextADInt_Adi_Authorization_Service(
    1178                 $this->getConfiguration(),
    1179                 $this->getUserManager(),
    1180                 $this->getRoleManager(),
    1181                 $this->getLoginState()
    1182             );
    1183         }
    1184 
    1185         return $this->authorizationService;
    1186     }
     1178    /**
     1179     * @return NextADInt_Adi_Authorization_Service
     1180     */
     1181    public function getAuthorizationService()
     1182    {
     1183        if ($this->authorizationService == null) {
     1184            $this->authorizationService = new NextADInt_Adi_Authorization_Service(
     1185                $this->getConfiguration(),
     1186                $this->getUserManager(),
     1187                $this->getRoleManager(),
     1188                $this->getLoginState()
     1189            );
     1190        }
     1191
     1192        return $this->authorizationService;
     1193    }
    11871194
    11881195    /**
     
    11941201     * @return NextADInt_Adi_User_LoginSucceededService
    11951202     */
    1196     public function getLoginSucceededService() {
     1203    public function getLoginSucceededService()
     1204    {
    11971205        if ($this->loginSucceededService == null) {
    11981206            $this->loginSucceededService = new NextADInt_Adi_User_LoginSucceededService(
     
    12071215        return $this->loginSucceededService;
    12081216    }
     1217
     1218    /**
     1219     * @var NextADInt_ActiveDirectory_Context
     1220     */
     1221    private $activeDirectoryContext;
     1222
     1223    /**
     1224     * @return mixed|NextADInt_ActiveDirectory_Context|void
     1225     */
     1226    public function getActiveDirectoryContext()
     1227    {
     1228        if ($this->activeDirectoryContext == null) {
     1229            // factory callback to create a new context
     1230            add_filter(NEXT_AD_INT_PREFIX . 'create_dependency_active_directory_context', function ($instance, NextADInt_Multisite_Configuration_Service $configuration) {
     1231                if (empty($instance)) {
     1232                    $instance = new NextADInt_ActiveDirectory_Context([$configuration->getOptionValue(NextADInt_Adi_Configuration_Options::DOMAIN_SID)]);
     1233                }
     1234
     1235                return $instance;
     1236            }, 10, 2);
     1237
     1238            $this->activeDirectoryContext = apply_filters(NEXT_AD_INT_PREFIX . 'create_dependency_active_directory_context', null, $this->getConfiguration());
     1239        }
     1240
     1241        return $this->activeDirectoryContext;
     1242    }
     1243
     1244    /**
     1245     * @var NextADInt_Adi_Authentication_SingleSignOn_Profile_Locator
     1246     */
     1247    private $ssoProfileLocator = null;
     1248
     1249    /**
     1250     * @return NextADInt_Adi_Authentication_SingleSignOn_Profile_Locator
     1251     * @since 2.0.0
     1252     */
     1253    public function getSsoProfileLocator()
     1254    {
     1255        if ($this->ssoProfileLocator == null) {
     1256            $this->ssoProfileLocator = new NextADInt_Adi_Authentication_SingleSignOn_Profile_Locator(
     1257                $this->getConfiguration()
     1258            );
     1259        }
     1260
     1261        return $this->ssoProfileLocator;
     1262    }
    12091263}
  • next-active-directory-integration/trunk/classes/Adi/Mail/Notification.php

    r1756617 r2513920  
    7777     * @return bool
    7878     */
    79     public function sendNotification(NextADInt_Adi_Mail_Message $mail, $useLocalWordPressUser = false, WP_User $wpUser)
     79    public function sendNotification(NextADInt_Adi_Mail_Message $mail, $useLocalWordPressUser, WP_User $wpUser)
    8080    {
    8181        $url = get_bloginfo('url');
     
    150150    {
    151151        $attributes = array('sn', 'givenname', 'mail');
    152         $userAttributeValues = $this->ldapConnection->findSanitizedAttributesOfUser($username, $attributes);
     152        $userAttributeValues = $this->ldapConnection->findSanitizedAttributesOfUser(NextADInt_Ldap_UserQuery::forPrincipal($username), $attributes);
    153153
    154154        return array(
  • next-active-directory-integration/trunk/classes/Adi/Role/Manager.php

    r2224724 r2513920  
    299299
    300300        $wpRoles = new WP_Roles();
     301       
    301302        foreach ($wpRoles->roles as $id => $object) {
    302             if ($id === 'zocker') {
    303                 continue;
    304             }
    305303            $result[$id] = $id;
    306304        }
  • next-active-directory-integration/trunk/classes/Adi/Synchronization/Abstract.php

    r1944146 r2513920  
    2525    protected $connectionDetails;
    2626
    27     /* @var int*/
     27    /* @var int */
    2828    private $time = 0;
    2929
     
    3535    /**
    3636     * @param NextADInt_Multisite_Configuration_Service $configuration
    37      * @param NextADInt_Ldap_Connection                 $connection
    38      * @param NextADInt_Ldap_Attribute_Service          $attributeService
     37     * @param NextADInt_Ldap_Connection $connection
     38     * @param NextADInt_Ldap_Attribute_Service $attributeService
    3939     * */
    4040    public function __construct(NextADInt_Multisite_Configuration_Service $configuration,
    41         NextADInt_Ldap_Connection $connection,
    42         NextADInt_Ldap_Attribute_Service $attributeService
    43     ) {
     41                                NextADInt_Ldap_Connection $connection,
     42                                NextADInt_Ldap_Attribute_Service $attributeService
     43    )
     44    {
    4445        $this->configuration = $configuration;
    4546        $this->connection = $connection;
     
    5657    {
    5758        if (NextADInt_Core_Util::native()->iniGet('max_execution_time') >= self::REQUIRED_EXECUTION_TIME_IN_SECONDS) {
    58             return; 
     59            return;
    5960        }
    6061
     
    120121        foreach ($users as $user) {
    121122            $guid = get_user_meta($user->ID, NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_OBJECT_GUID, true);
    122             $userDomainSid = get_user_meta(
    123                 $user->ID, NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_DOMAINSID, true
    124             );
    125 
    126             if ($this->isVerifiedDomainMember($userDomainSid)) {
    127                 $wpUsername = $user->user_login;
    128                 $r[NextADInt_Core_Util_StringUtil::toLowerCase($guid)] = $wpUsername;
    129             } else {
    130                 $this->logger->warning('User with name ' . $user->user_login . 'is not a member of the target domain.');
    131             }
     123            $wpUsername = $user->user_login;
     124            $r[NextADInt_Core_Util_StringUtil::toLowerCase($guid)] = $wpUsername;
    132125        }
    133126
     
    147140    {
    148141        $args = array(
    149             'blog_id'    => get_current_blog_id(),
    150             'meta_key'   => NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_ACTIVE_DIRECTORY_SAMACCOUNTNAME,
     142            'blog_id' => get_current_blog_id(),
     143            'meta_key' => NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_ACTIVE_DIRECTORY_SAMACCOUNTNAME,
    151144            'meta_query' => array(
    152145                'relation' => 'AND',
    153146                array(
    154                     'key'     => NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_ACTIVE_DIRECTORY_SAMACCOUNTNAME,
    155                     'value'   => '',
     147                    'key' => NEXT_AD_INT_PREFIX . NextADInt_Adi_User_Persistence_Repository::META_KEY_ACTIVE_DIRECTORY_SAMACCOUNTNAME,
     148                    'value' => '',
    156149                    'compare' => '!=',
    157150                ),
    158151            ),
    159             'exclude'    => array(1)
     152            'exclude' => array(1)
    160153        );
    161154
     
    174167            );
    175168
    176             if ($this->isVerifiedDomainMember($userDomainSid)) {
    177                 array_push($r, $user);
     169            $sid = NextADInt_ActiveDirectory_Sid::of($userDomainSid);
     170
     171            if (!$this->connection->getActiveDirectoryContext()->isMember($sid)) {
     172                $this->logger->warning('User with name ' . $user->user_login . 'is not a member of one of the configured domains.');
     173                continue;
    178174            }
    179         }
    180 
    181         $this->logger->debug(sizeof($r) . " of " . sizeof($users) . " users in this blog are assigned to the domain SID '" . $this->connection->getDomainSid() . "'");
     175
     176            array_push($r, $user);
     177        }
     178
     179        $this->logger->debug(sizeof($r) . " of " . sizeof($users) . " users in this blog are assigned to one of configured domain SIDs " . $this->connection->getActiveDirectoryContext());
    182180
    183181        return $r;
     
    188186     * Workaround to prevent adLDAP from syncing "Array" as a value for an attribute to the Active Directory.
    189187     *
    190      * @param array  $attributesToSync
     188     * @param array $attributesToSync
    191189     * @param string $metaKey
    192190     *
     
    203201
    204202    /**
    205      * Check if the user is a member of the Active Directory domain connected to the WordPress site via its domain SID
    206      *
    207      * @param string $userDomainSid
    208      *
    209      * @return bool true if user is member of domain
    210      */
    211     public function isVerifiedDomainMember($userDomainSid)
    212     {
    213         if ($userDomainSid == $this->connection->getDomainSid()) {
    214             return true;
    215         }
    216        
    217         return false;
    218     }
    219 
    220     /**
    221203     * Check if username is inside the current linked domain
    222204     *
     
    224206     * @return bool
    225207     */
    226     public function isUsernameInDomain($username) {
     208    public function isUsernameInDomain($username)
     209    {
    227210        // TODO this method is only called from the child classes after the authentication is succeeded. Can we re-use the user_info from the authentication?
    228211        // TODO this would prevent a second LDAP call
    229212        $adLdap = $this->connection->getAdLdap();
    230         $binarySid = $adLdap->user_info($username, array("objectsid"));
    231         $stringSid = $adLdap->convertObjectSidBinaryToString($binarySid[0]["objectsid"][0]);
    232         $usersDomainSid = NextADInt_Core_Util_StringUtil::objectSidToDomainSid($stringSid);
    233 
    234         if (empty($binarySid)) {
     213        $userInfo = $adLdap->user_info($username, array("objectsid"));
     214
     215        if (empty($userInfo)) {
    235216            $this->logger->error("SID of user '$username' could not be retrieved. Is the base DN correct? Does the userPrincipalName '$username' exist and not only its sAMAccountName?'");
    236217            return false;
    237218        }
    238219
    239         if ($this->isVerifiedDomainMember($usersDomainSid)) {
     220        $objectSid = NextADInt_ActiveDirectory_Sid::of($userInfo[0]["objectsid"][0]);
     221
     222        try {
     223            $this->connection->getActiveDirectoryContext()->checkMembership($objectSid);
    240224            return true;
    241         }
    242 
    243         $this->logger->warn('User ' . $username . ' with SID ' . $usersDomainSid . ' (domain SID: ' . $usersDomainSid . ') is not member of domain with domain SID "' . $this->connection->getDomainSid() . "'");
     225        } catch (Exception $e) {
     226            $this->logger->warn('User ' . $username . ' is not a domain member: ' . $e->getMessage());
     227        }
     228
    244229        return false;
    245230    }
  • next-active-directory-integration/trunk/classes/Adi/Synchronization/WordPress.php

    r2331595 r2513920  
    228228     * Convert the given array into our necessary format.
    229229     *
    230      * @param $adUsers
     230     * @param $adUsers list of sAMAccountNames
    231231     *
    232232     * @return array|hashmap key is Active Directory objectGUID, value is username
     
    237237
    238238        foreach ($adUsers as $adUser) {
    239             $attributes = $this->attributeService->findLdapAttributesOfUsername($adUser);
     239            $attributes = $this->attributeService->findLdapAttributesOfUser(NextADInt_Ldap_UserQuery::forPrincipal($adUser));
    240240            $guid = $attributes->getFilteredValue(NextADInt_Adi_User_Persistence_Repository::META_KEY_OBJECT_GUID);
    241241
     
    275275        $uac = $attributes[$key][0];
    276276
    277         return $uac;
    278     }
    279 
    280     /**
    281      * Is the account a normal account ?
     277        // @see GH-132: https://github.com/NeosIT/active-directory-integration2/issues/132
     278        // With PHP 8 we got hit by https://github.com/php/php-src/pull/5331
     279        return (int)$uac;
     280    }
     281
     282    /**
     283     * Is the account a normal account?
    282284     * Checking for flags that should not be set for a normal user account ( http://www.selfadsi.org/ads-attributes/user-userAccountControl.htm )
    283285     *
     
    289291    {
    290292
    291         // ADI-517 Improved logging for UAC Binary Flag check to make it more transparent for the user and improve debugging.
     293        // @see ADI-517: Improved logging for UAC Binary Flag check to make it more transparent for the user and improve debugging.
    292294        switch ($uac) {
    293295            case (($uac & self::UF_INTERDOMAIN_TRUST_ACCOUNT) === self::UF_INTERDOMAIN_TRUST_ACCOUNT):
     
    357359     */
    358360    public function disableUserWithoutValidGuid($ldapAttributes, $credentials) {
    359 
    360         if (null === $ldapAttributes->getFilteredValue('objectguid')) {
    361             // Set domain sid to empty, to prevent non existing user from getting used for sync to wordpress
    362             $ldapAttributes->setDomainSid('empty');
    363 
    364             $adiUser = $this->userManager->createAdiUser($credentials, $ldapAttributes);
    365             $status = $this->createOrUpdateUser($adiUser);
    366 
    367             $this->userManager->disable($adiUser->getId(), 'User no longer exists in Active Directory.');
    368 
    369             $this->logger->warn('Removed domain sid for user ' . $credentials->getLogin());
    370 
    371             return $status;
    372         }
     361        if (!empty($ldapAttributes->getFilteredValue('objectguid'))) {
     362            return;
     363        }
     364
     365        // Set domain sid to empty, to prevent non existing user from getting used for sync to wordpress
     366        $ldapAttributes->setDomainSid('empty');
     367        $this->logger->warn('Removed domain sid for user ' . $credentials->getLogin());
     368
     369        $adiUser = $this->userManager->createAdiUser($credentials, $ldapAttributes);
     370        $status = $this->createOrUpdateUser($adiUser);
     371
     372        $this->userManager->disable($adiUser->getId(), 'User no longer exists in Active Directory.');
     373
     374        return $status;
    373375    }
    374376
     
    398400
    399401        // ADI-204: in contrast to the login process we use the guid to determine the LDAP attributes
    400         $ldapAttributes = $this->attributeService->findLdapAttributesOfUser($credentials, $guid);
    401 
     402        $ldapAttributes = $this->attributeService->resolveLdapAttributes(NextADInt_Ldap_UserQuery::forGuid($guid, $credentials));
    402403
    403404        // NADIS-1: Checking if the GUID of a user is valid when user does not exist in the active directory anymore. Therefore, disable user and remove domain sid
     
    415416
    416417        // ADI-235: add domain SID
    417         $ldapAttributes->setDomainSid($this->connection->getDomainSid());
     418        $userSid = $ldapAttributes->getFilteredValue('objectsid');
     419        $ldapAttributes->setDomainSid(NextADInt_ActiveDirectory_Sid::of($userSid)->getDomainPartAsSid()->getFormatted());
    418420
    419421        $elapsedTimeLdap = time() - $startTimerLdap;
  • next-active-directory-integration/trunk/classes/Adi/User/LoginSucceededService.php

    r2069979 r2513920  
    5050        NextADInt_Ldap_Connection $ldapConnection,
    5151        NextADInt_Multisite_Configuration_Service $configuration
    52     ) {
     52    )
     53    {
    5354        $this->loginState = $loginState;
    5455        $this->attributeService = $attributeService;
     
    9394    public function updateOrCreateUser(
    9495        $wpUser
    95     ) {
    96         if ( ! $this->loginState->isAuthenticated() || $this->loginState->isAuthorized() === false) {
     96    )
     97    {
     98        if (!$this->loginState->isAuthenticated() || $this->loginState->isAuthorized() === false) {
    9799            return false;
    98100        }
     
    104106        $authenticatedCredentials = $wpUser;
    105107
     108
    106109        // ADI-204: during login we have to use the authenticated user principal name
    107         $ldapAttributes = $this->attributeService->findLdapAttributesOfUser($authenticatedCredentials, null);
     110        $ldapAttributes = $this->attributeService->resolveLdapAttributes($authenticatedCredentials->toUserQuery());
    108111
    109112        // ADI-395: wrong base DN leads to exception during Test Authentication
     
    129132            $authenticatedCredentials, $ldapAttributes);
    130133
    131         if ( ! $preCreateStatus) {
     134        if (!$preCreateStatus) {
    132135            $this->logger->debug('The preCreateStatus returned false. The user will not be created or updated. If this behavior is not intended, please verify your custom logic using the "auth_before_create_or_update_user" filter works properly.');
    133136
     
    138141
    139142        // ADI-309: domain SID gets not synchronized
    140         $domainSid = $this->ldapConnection->getDomainSid();
    141         $adiUser->getLdapAttributes()->setDomainSid($domainSid);
     143        $userSid = NextADInt_ActiveDirectory_Sid::of($ldapAttributes->getFilteredValue('objectsid'));
     144        $adiUser->getLdapAttributes()->setDomainSid($userSid->getDomainPartAsSid()->getFormatted());
    142145
    143146        if ($adiUser->getId()) {
     
    182185        // In 1.0.x users were created even if auoCreateUser was false but they had a role equivalent group.
    183186        // With 2.0.x the user is only created if the option "Auto Create User" is enabled.
    184         if ( ! $autoCreateUser) {
     187        if (!$autoCreateUser) {
    185188            $error = 'This user exists in Active Directory, but not in the local WordPress instance. The option "Auto Create User" is __not__ enabled but should be.';
    186189            $this->logger->error($error);
     
    195198
    196199        // if $this->userManager is null, then do not create the user
    197         if ( ! $this->userManager) {
     200        if (!$this->userManager) {
    198201            $this->logger->warn(
    199202                "User '{$user->getUsername()}' will not be created because the user login is only simulated."
     
    207210    }
    208211
    209     /**
    210     * If "Auto Update User" is enabled, the user's profile data is updated. In any case if a $userRole is present, it is synchronized with the backend.
    211     *
    212     * @param NextADInt_Adi_User $user
    213     *
    214     * @return false|WP_User false if creation is only simulated; int if user has been updated.
    215     * @throws Exception
    216     */
     212    /**
     213    * If "Auto Update User" is enabled, the user's profile data is updated. In any case if a $userRole is present, it is synchronized with the backend.
     214    *
     215    * @param NextADInt_Adi_User $user
     216    *
     217    * @return false|WP_User false if creation is only simulated; int if user has been updated.
     218    * @throws Exception
     219    */
    217220    function updateUser(NextADInt_Adi_User $user)
    218221    {
    219222        $this->logger->debug("Checking preconditions for updating existing user " . $user);
    220223
    221         $autoUpdateUser     = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::AUTO_UPDATE_USER);
     224        $autoUpdateUser = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::AUTO_UPDATE_USER);
    222225        $autoUpdatePassword = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::AUTO_UPDATE_PASSWORD);
    223226
  • next-active-directory-integration/trunk/classes/Core/Persistence/WordPressRepository.php

    r1541870 r2513920  
    108108     * @param array $args
    109109     * @param       $mode
     110     * @deprecated
    110111     *
    111112     * @return array|null|object
    112113     */
    113     public function wpdb_get_results($sql, $args = array(), $mode)
     114    public function wpdb_get_results($sql, $args, $mode)
    114115    {
    115116        global $wpdb;
  • next-active-directory-integration/trunk/classes/Core/Util/StringUtil.php

    r1608780 r2513920  
    254254    }
    255255
     256
     257    /**
     258     * Check if the given text ends with the given string.
     259     *
     260     * Thanks to:
     261     * http://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php?answertab=votes#tab-top
     262     *
     263     * @param $needle
     264     * @param $haystack
     265     *
     266     * @return bool
     267     */
     268    public static function endsWith($needle, $haystack)
     269    {
     270        $length = strlen( $needle );
     271        if( !$length ) {
     272            return true;
     273        }
     274        return substr( $haystack, -$length ) === $needle;
     275    }
     276
    256277    /**
    257278     * Convert the given string to lowercase using {@link mb_strtolower}.
  • next-active-directory-integration/trunk/classes/Ldap/Attribute/Repository.php

    r1944146 r2513920  
    5858            'objectguid',
    5959            'domainsid',
     60            'objectsid',
    6061        );
    6162
  • next-active-directory-integration/trunk/classes/Ldap/Attribute/Service.php

    r1756617 r2513920  
    5656     * @return array
    5757     */
    58     function parseLdapResponse($attributeNames = array(), $ldapData)
     58    function parseLdapResponse($attributeNames, $ldapData)
    5959    {
    6060        NextADInt_Core_Assert::notNull($attributeNames);
     
    141141
    142142    /**
    143      * Find all LDAP attributes for the user which have been enabled in the blog or multisite
    144      *
    145      * @param string $username GUID, sAMAccountName or userPrincipalName
    146      * @param bool $isGUID
     143     * Find all LDAP attributes for a user based upon the given query
     144     *
     145     * @param NextADInt_Ldap_UserQuery $userQuery GUID, sAMAccountName or userPrincipalName
    147146     *
    148147     * @return NextADInt_Ldap_Attributes
    149148     */
    150     public function findLdapAttributesOfUsername($username, $isGUID = false)
     149    public function findLdapAttributesOfUser(NextADInt_Ldap_UserQuery $userQuery)
    151150    {
    152151        $attributeNames = $this->attributeRepository->getAttributeNames();
     
    154153
    155154        // ADI-145: provide API
    156         $attributeNames = apply_filters(NEXT_AD_INT_PREFIX .  'ldap_filter_synchronizable_attributes', $attributeNames, $username, $isGUID);
    157 
    158         if (!empty($username)) {
     155        $attributeNames = apply_filters(NEXT_AD_INT_PREFIX . 'ldap_filter_synchronizable_attributes', $attributeNames, $userQuery);
     156
     157        if (!empty($userQuery->getPrincipal())) {
    159158            // make sure that only non-empty usernames are resolved
    160             $raw = $this->ldapConnection->findAttributesOfUser($username, $attributeNames, $isGUID);
     159            $raw = $this->ldapConnection->findAttributesOfUser($userQuery, $attributeNames);
    161160        }
    162161
     
    167166
    168167    /**
    169      * Find the LDAP attributes for the given credentials or guid.
    170      *
    171      * @param NextADInt_Adi_Authentication_Credentials $credentials
    172      * @param string $guid
    173      *
     168     * Based upon the query, different markers are tried to find the user:
     169     * <ul>
     170     * <li>if the query is specified as GUID; this if searched first</li>
     171     * <li>userPrincipalName is tried as second</li>
     172     * <li>sAMAccountNAme is tried last in line. This can deliver multiple results in an AD forest. You have to use the Active Directory Forest premium extension</li>
     173     * </ul>
     174     *
     175     * @param NextADInt_Ldap_UserQuery $userQuery
    174176     * @return NextADInt_Ldap_Attributes
    175      */
    176     public function findLdapAttributesOfUser(NextADInt_Adi_Authentication_Credentials $credentials, $guid)
    177     {
    178         if (isset($guid)) {
    179             $ldapAttributes = $this->findLdapAttributesOfUsername($guid, true);
    180         }
    181 
     177     * @see ADI-713
     178     */
     179    public function resolveLdapAttributes(NextADInt_Ldap_UserQuery $userQuery)
     180    {
     181        /**
     182         * @var NextADInt_Ldap_Attributes
     183         */
     184        $ldapAttributes = null;
     185
     186        // GUID has priority
     187        if ($userQuery->isGuid()) {
     188            $ldapAttributes = $this->findLdapAttributesOfUser($userQuery);
     189        }
     190
     191        // NADIS-133: When using a Global Catalog (GC), users with same sAMAccountName but different userPrincipalNames are not assigned correct during authentication
     192        // this requires us to lookup the userPrincipalName *before* the sAMAccountName
    182193        if (empty($ldapAttributes) || (false == $ldapAttributes->getRaw())) {
    183             $ldapAttributes = $this->findLdapAttributesOfUsername($credentials->getSAMAccountName());
    184         }
    185 
     194            $ldapAttributes = $this->findLdapAttributesOfUser($userQuery->withPrincipal($userQuery->getCredentials()->getUserPrincipalName()));
     195        }
     196
     197        // fallback to the sAMAccountName
    186198        if (empty($ldapAttributes) || (false == $ldapAttributes->getRaw())) {
    187             $ldapAttributes = $this->findLdapAttributesOfUsername($credentials->getUserPrincipalName());
     199            $ldapAttributes = $this->findLdapAttributesOfUser($userQuery->withPrincipal($userQuery->getCredentials()->getSAMAccountName()));
    188200        }
    189201
     
    196208
    197209    /**
    198      * Find the custom LDAP attribute for the given username
    199      * @param string $username
     210     * Find the custom LDAP attribute for the given user query
     211     * @param NextADInt_Ldap_UserQuery $userQuery
    200212     * @param string $attribute
    201213     * @return bool|string false if attribute is empty or not inside the returned array of attribute values
    202214     */
    203     public function findLdapCustomAttributeOfUsername($username, $attribute)
     215    public function findLdapCustomAttributeOfUser(NextADInt_Ldap_UserQuery $userQuery, $attribute)
    204216    {
    205217        $attributes = array($attribute);
    206218
    207         $raw = $this->ldapConnection->findAttributesOfUser($username, $attributes, false);
     219        $raw = $this->ldapConnection->findAttributesOfUser($userQuery, $attributes);
    208220        $filtered = $this->parseLdapResponse($attributes, $raw);
    209221
     
    217229
    218230    /**
    219      * Find a single attribute for the give credentials. It first tests the sAMAccountName and then the userPrincipalName of the credentials
     231     * Find a single attribute for the given credentials. It first tests the userPrincipalName  and then the sAMAccountName of the credentials
    220232     *
    221233     * @param NextADInt_Adi_Authentication_Credentials $credentials
     
    223235     * @return string|bool if attribute could not be found it returns false
    224236     */
    225     public function findLdapCustomAttributeOfUser(NextADInt_Adi_Authentication_Credentials $credentials, $attribute)
    226     {
    227         $value = $this->findLdapCustomAttributeOfUsername($credentials->getUserPrincipalName(), $attribute);
     237    public function resolveLdapCustomAttribute(NextADInt_Ldap_UserQuery $userQuery, $attribute)
     238    {
     239        $value = $this->findLdapCustomAttributeOfUser($userQuery->withPrincipal($userQuery->getCredentials()->getUserPrincipalName()), $attribute);
    228240
    229241        if (false === $value) {
    230             $this->logger->warn("Could not locate custom attribute '" . $attribute . "' for userPrincipalName '" . $credentials->getUserPrincipalName() . "'. Fall back to sAMAccountName...'");
    231 
    232             $value = $this->findLdapCustomAttributeOfUsername($credentials->getSAMAccountName(), $attribute);
     242            $this->logger->warn("Could not locate custom attribute '" . $attribute . "' for query '" . $userQuery->getCredentials()->getUserPrincipalName() . "'. Fall back to sAMAccountName...'");
     243
     244            $value = $this->findLdapCustomAttributeOfUser($userQuery->withPrincipal($userQuery->getCredentials()->getSAMAccountName()), $attribute);
    233245        }
    234246
     
    240252     *
    241253     * @param NextADInt_Adi_Authentication_Credentials $credentials
    242      * @return NextADInt_Ldap_Attributes|false false if username account could not be found
     254     * @return ActiveDirectory_Sid|false false if username account could not be found
    243255     */
    244256    public function getObjectSid(NextADInt_Adi_Authentication_Credentials $credentials)
    245257    {
    246258        NextADInt_Core_Assert::notNull($credentials, "credentials must not be null");
    247         $objectSid = $this->findLdapCustomAttributeOfUser($credentials, 'objectsid');
     259        $objectSid = $this->findLdapCustomAttributeOfUser($credentials->toUserQuery(), 'objectsid');
    248260
    249261        if (false === $objectSid) {
     
    251263        }
    252264
    253         return $this->ldapConnection->getAdLdap()->convertObjectSidBinaryToString($objectSid);
     265        return NextADInt_ActiveDirectory_Sid::of($objectSid);
    254266    }
    255267
     
    259271     * @return string|boolean
    260272     */
    261     public function getNetBiosName() {
     273    public function getNetBiosName()
     274    {
    262275        $netBiosName = $this->ldapConnection->findNetBiosName();
    263276
  • next-active-directory-integration/trunk/classes/Ldap/Connection.php

    r2331595 r2513920  
    2828    private $logger;
    2929
    30     /* @var string */
    31     private $siteDomainSid;
     30    /* @var NextADInt_ActiveDirectory_Context */
     31    private $activeDirectoryContext;
    3232
    3333    /**
    3434     * @param NextADInt_Multisite_Configuration_Service $configuration
    35      */
    36     public function __construct(NextADInt_Multisite_Configuration_Service $configuration)
     35     * @param NextADInt_ActiveDirectory_Context $activeDirectoryContext
     36     */
     37    public function __construct(NextADInt_Multisite_Configuration_Service $configuration,
     38                                NextADInt_ActiveDirectory_Context $activeDirectoryContext
     39    )
    3740    {
    3841        if (!class_exists('adLDAP')) {
     
    4043            require_once NEXT_AD_INT_PATH . '/vendor/adLDAP/adLDAP.php';
    4144        }
    42        
     45
    4346        $this->configuration = $configuration;
     47        $this->activeDirectoryContext = $activeDirectoryContext;
    4448
    4549        $this->logger = NextADInt_Core_Logger::getLogger();
     50    }
     51
     52    /**
     53     * Register additional hooks
     54     * @since 2.0.0
     55     */
     56    public function register()
     57    {
     58        // ADI-713: Map user information when search for GUID, userPrincipalName or sAMAccountName
     59        add_filter(NEXT_AD_INT_PREFIX . 'ldap_map_userinfo', array($this, 'mapUserInfo'), 10, 5);
    4660    }
    4761
     
    8195
    8296        $config = array(
    83             'account_suffix'     => '',
    84             'base_dn'            => $this->getBaseDn($connectionDetails),
     97            'account_suffix' => '',
     98            'base_dn' => $this->getBaseDn($connectionDetails),
    8599            'domain_controllers' => $this->getDomainControllers($connectionDetails),
    86             'ad_port'            => $this->getAdPort($connectionDetails),
    87             'use_tls'            => $useTls,    //StartTLS
    88             //ADI-482 enable LDAPS support
    89             'use_ssl'            => $useSsl,  //LDAP over Ssl
    90             'network_timeout'    => $this->getNetworkTimeout($connectionDetails),
    91             'allow_self_signed' => $this->getAllowSelfSigned($connectionDetails),
    92             'ad_username'        => $connectionDetails->getUsername(),
    93             'ad_password'        => $connectionDetails->getPassword(),
     100            'ad_port' => $this->getAdPort($connectionDetails),
     101            'use_tls' => $useTls,    // STARTTLS
     102            // ADI-482 enable LDAPS support
     103            'use_ssl' => $useSsl,  // LDAP over SSL
     104            'network_timeout' => $this->getNetworkTimeout($connectionDetails),
     105            'allow_self_signed' => $this->getAllowSelfSigned($connectionDetails),
     106            'ad_username' => $connectionDetails->getUsername(),
     107            'ad_password' => $connectionDetails->getPassword(),
    94108        );
    95109
     
    189203    }
    190204
    191     /**
    192     * Return the usage of SSL based upon the $connectionDetails. If the usage of SSL is not set the usage of SSL of the current blog instance is returned.
    193     *
    194     * @param NextADInt_Ldap_ConnectionDetails $connectionDetails
    195     *
    196     * @return bool
    197     */
    198     public function getUseSsl(NextADInt_Ldap_ConnectionDetails $connectionDetails)
    199     {
    200         return $this->getEncryption($connectionDetails) === NextADInt_Multisite_Option_Encryption::LDAPS;
    201     }
     205    /**
     206    * Return the usage of SSL based upon the $connectionDetails. If the usage of SSL is not set the usage of SSL of the current blog instance is returned.
     207    *
     208    * @param NextADInt_Ldap_ConnectionDetails $connectionDetails
     209    *
     210    * @return bool
     211    */
     212    public function getUseSsl(NextADInt_Ldap_ConnectionDetails $connectionDetails)
     213    {
     214        return $this->getEncryption($connectionDetails) === NextADInt_Multisite_Option_Encryption::LDAPS;
     215    }
    202216
    203217    /**
     
    233247            $allowSelfSigned = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::ALLOW_SELF_SIGNED);
    234248        }
    235        
     249
    236250        return $allowSelfSigned;
    237251    }
     
    284298        return is_object($this->adldap);
    285299    }
    286    
     300
    287301    /**
    288302     *  Find the sAMAccountName associated with a ProxyAddress
    289      * 
    290      *  @param string $proxyAddress The proxy address to check
    291      * 
    292      *  @return false if not found or the sAMAccountName.
     303     *
     304     * @param string $proxyAddress The proxy address to check
     305     *
     306     * @return false if not found or the sAMAccountName.
    293307     */
    294308    public function findByProxyAddress($proxyAddress)
     
    382396     * Lookup the requested LDAP attributes for the user from the underlying Active Directory connection
    383397     *
    384      * @param string $username
    385      * @param array  $attributeNames
    386      * @param bool   $isGUID
     398     * @param NextADInt_Ldap_UserQuery $userQuery
     399     * @param array $attributeNames
    387400     *
    388401     * @return array
    389402     */
    390     public function findAttributesOfUser($username, $attributeNames, $isGUID = false)
     403    public function findAttributesOfUser(NextADInt_Ldap_UserQuery $userQuery, $attributeNames)
    391404    {
    392405        $adLdap = $this->getAdLdap();
    393406
    394         $userInfo = $adLdap->user_info($username, $attributeNames, $isGUID);
    395 
    396         if ($userInfo === false) {
    397             $this->logger->warn("Attributes for '$username': could not be loaded. Does the sAMAccountName or userPrincipalName exist? Is the provided base DN valid?");
     407        $matchesFromLdap = $adLdap->user_info($userQuery->getPrincipal(), $attributeNames, $userQuery->isGuid());
     408
     409        if ($matchesFromLdap === false) {
     410            $this->logger->warn("Query '$userQuery' did not return any values. Does the sAMAccountName or userPrincipalName exist? Is the provided base DN valid? Is the Kerberos realm mapped");
    398411
    399412            return false;
    400413        }
    401414
    402         // user does exist, get first element
    403         $userInfo = $userInfo[0];
    404 
    405         $this->logger->debug("UserInfo for user '$username': " . $this->__debug($userInfo));
     415        // ADI-713: try to extract the user's information from a list of arrays
     416        $userInfo = apply_filters(NEXT_AD_INT_PREFIX . 'ldap_map_userinfo', false, $matchesFromLdap, $matchesFromLdap['count'], $userQuery, $attributeNames);
     417
     418        if ($userInfo) {
     419            $this->logger->debug("UserInfo for user '" . $userQuery . "': " . $this->__debug($userInfo));
     420        }
    406421
    407422        return $userInfo;
     423    }
     424
     425    /**
     426     * After the Active Directory has been queried to look for a GUID, userPrincipalName or sAMAccountName, this method will be called.
     427     *
     428     * @param boolean|mixed $bestMatch The best match being used. It is false if no match has been found yet.
     429     * @param array $matchesFromLdap
     430     * @param integer $totalMatches number of matches; due to the adLDAP structure
     431     * @param NextADInt_Ldap_UserQuery $userQuery
     432     * @param array $attributeNames
     433     * @return array|boolean the $bestMatch exactly one match or false
     434     * @see ADI-713
     435     * @since 2.1.13
     436     */
     437    public function mapUserInfo($bestMatch, $matchesFromLdap, $totalMatches, NextADInt_Ldap_UserQuery $userQuery, $attributeNames)
     438    {
     439        // there has not been a best match specified; this method is the fallback option
     440        if (!$bestMatch) {
     441            // we got more than one result for the DC/GC; this can happen if a sAMAccountName is queried inside a AD forest
     442            if ($totalMatches > 1) {
     443                $this->logger->error('The user query "' . $userQuery . "' returned " . $totalMatches . ' results. You have to do additional configuration if you are running NADI inside an AD forest.');
     444                $bestMatch = false;
     445            } // we have exactly one result, so we will use it
     446            else {
     447                $bestMatch = $matchesFromLdap[0];
     448            }
     449        }
     450
     451        return $bestMatch;
    408452    }
    409453
     
    427471        }
    428472
    429         $this->logger->debug("Found NetBIOS name '" . $netbios . "' for '" . $this->getDomainSid());
     473        $this->logger->debug("Found NetBIOS name '" . $netbios . "' for domain SIDs " . $this->activeDirectoryContext);
    430474
    431475        return $netbios;
     
    440484     * @return string
    441485     */
    442     public function __debug($userInfo = array()) {
     486    private function __debug($userInfo = array())
     487    {
    443488        $result = "";
    444489        $maxOutputChars = 32;
     
    458503
    459504                // remove any linebreaks or carriagereturns from the attributes
    460                 $element = preg_replace("/\r\n|\r|\n/",'',$element);
     505                $element = preg_replace("/\r\n|\r|\n/", '', $element);
    461506
    462507                if ($attribute === "objectguid") {
     
    466511                        $this->logger->error("An exception occurred trying to convert binary to GUID. Exception: " . $exception->getMessage());
    467512                    }
    468 
    469513                }
    470514
    471                 $result .=  NextADInt_Core_Util_StringUtil::firstChars($element, 500);
     515                $result .= NextADInt_Core_Util_StringUtil::firstChars($element, 500);
    472516
    473517            }
     
    488532     * Lookup all requested attributes and instantly sanitize them.
    489533     *
    490      * @param string $username
    491      * @param array  $attributes
     534     * @param NextADInt_Ldap_UserQuery $userQuery
     535     * @param array $attributes
    492536     *
    493537     * @return array
    494538     */
    495     public function findSanitizedAttributesOfUser($username, $attributes)
    496     {
    497         $userInfo = $this->findAttributesOfUser($username, $attributes);
     539    public function findSanitizedAttributesOfUser(NextADInt_Ldap_UserQuery $userQuery, $attributes)
     540    {
     541        $userInfo = $this->findAttributesOfUser($userQuery, $attributes);
    498542        $sanitized = array();
    499543
     
    512556     *
    513557     * @param WP_User $wpUser
    514      * @param array  $attributes Map with attributes and their values
     558     * @param array $attributes Map with attributes and their values
    515559     *
    516560     * @return bool
     
    587631     *
    588632     * @param string $domainController
    589      * @param int    $port
    590      * @param int    $timeout
     633     * @param int $port
     634     * @param int $timeout
    591635     *
    592636     * @return bool true if port could be opened, false if port could not be opened or fsockopen is not available.
     
    675719     * @return array
    676720     */
    677     function filterDomainMembers($members = array()) {
     721    function filterDomainMembers($members = array())
     722    {
    678723        $adLdap = $this->getAdLdap();
    679         $siteDomainSid = $this->getDomainSid();
    680724        $r = array();
    681725
    682726        foreach ($members as $member) {
    683727            $userInfo = $adLdap->user_info($member, array('objectsid'));
    684             $userSid = $adLdap->convertObjectSidBinaryToString($userInfo[0]["objectsid"][0]);
    685 
    686             if (strpos($userSid, $siteDomainSid) !== false) {
    687                 $r[NextADInt_Core_Util_StringUtil::toLowerCase($member)] = $member;
    688             }
     728
     729            $objectSid = NextADInt_ActiveDirectory_Sid::of($userInfo[0]["objectsid"][0]);
     730
     731            if (!$this->activeDirectoryContext->isMember($objectSid)) {
     732                $this->logger->debug("Object '" . $objectSid->getFormatted() . "' does not belong to one of the configured domains of " . $this->activeDirectoryContext);
     733                continue;
     734            }
     735
     736            $r[NextADInt_Core_Util_StringUtil::toLowerCase($member)] = $member;
    689737        }
    690738
    691739        return $r;
    692     }
    693 
    694     /**
    695      * Return the domain SID of the current synchronization
    696      *
    697      * @return mixed|string
    698      */
    699     public function getDomainSid() {
    700         if (empty($this->siteDomainSid)) {
    701             $this->siteDomainSid = $this->configuration->getOptionValue(NextADInt_Adi_Configuration_Options::DOMAIN_SID);
    702         }
    703 
    704         return $this->siteDomainSid;
    705740    }
    706741
     
    739774        return false;
    740775    }
     776
     777    /**
     778     * @return NextADInt_ActiveDirectory_Context
     779     */
     780    public function getActiveDirectoryContext()
     781    {
     782        return $this->activeDirectoryContext;
     783    }
    741784}
  • next-active-directory-integration/trunk/classes/Multisite/Configuration/Persistence/BlogConfigurationRepository.php

    r2331595 r2513920  
    4141    private $defaultProfileRepository;
    4242
    43     /**
    44      * @param NextADInt_Multisite_Option_Sanitizer                                         $sanitizer
    45      * @param NextADInt_Core_Encryption                                                    $encryptionHandler
    46      * @param NextADInt_Multisite_Option_Provider                                          $optionProvider
     43    private $siteToProfileCache = array();
     44
     45    /**
     46     * @param NextADInt_Multisite_Option_Sanitizer $sanitizer
     47     * @param NextADInt_Core_Encryption $encryptionHandler
     48     * @param NextADInt_Multisite_Option_Provider $optionProvider
    4749     * @param NextADInt_Multisite_Configuration_Persistence_ProfileConfigurationRepository $profileConfigurationRepository
    48      * @param NextADInt_Multisite_Configuration_Persistence_DefaultProfileRepository       $defaultProfileRepository
     50     * @param NextADInt_Multisite_Configuration_Persistence_DefaultProfileRepository $defaultProfileRepository
    4951     */
    5052    public function __construct(NextADInt_Multisite_Option_Sanitizer $sanitizer,
     
    5355                                NextADInt_Multisite_Configuration_Persistence_ProfileConfigurationRepository $profileConfigurationRepository,
    5456                                NextADInt_Multisite_Configuration_Persistence_DefaultProfileRepository $defaultProfileRepository
    55     ) {
     57    )
     58    {
    5659        $this->sanitizer = $sanitizer;
    5760        $this->encryptionHandler = $encryptionHandler;
     
    107110     * Moreover this method sanitize, decrypt etc. the value.
    108111     *
    109      * @param int    $siteSiteId
     112     * @param int $siteId
    110113     * @param string $optionName
    111114     *
    112115     * @return null|string
    113116     */
    114     public function findSanitizedValue($siteSiteId, $optionName)
    115     {
    116         //prevent change of associated profile
     117    public function findSanitizedValue($siteId, $optionName)
     118    {
     119        // prevent change of associated profile
    117120        if (self::PROFILE_ID === $optionName) {
    118121            return null;
    119122        }
    120123
    121         if ($this->isOptionHandledByProfile($siteSiteId, $optionName)) {
    122             $profileId = $this->findProfileId($siteSiteId);
    123 
    124             return $this->profileConfigurationRepository->findSanitizedValue($profileId, $optionName);
    125         }
    126 
    127         $optionValue = $this->findRawValue($siteSiteId, $optionName);
     124        $optionValue = $this->findRawValue($siteId, $optionName);
     125        $noOptionValueInSite = $optionValue == null;
     126        $profileId = $this->findProfileId($siteId);
     127
     128        // #124: when a profile is connected and no value has been yet inside the blog, we have to return the profile's value
     129        if ($profileId) {
     130            // and either no value for this option has been defined or it's handled by the profile
     131            if ($noOptionValueInSite || $this->isOptionHandledByProfile($siteId, $optionName)) {
     132                return $this->profileConfigurationRepository->findSanitizedValue($profileId, $optionName);
     133            }
     134        }
     135
    128136        $optionMetadata = $this->optionProvider->get($optionName);
    129137
    130         if (false === $optionValue) {
    131             $optionValue = $this->getDefaultValue($siteSiteId, $optionName, $optionMetadata);
     138        if (null === $optionValue) {
     139            $optionValue = $this->getDefaultValue($siteId, $optionName, $optionMetadata);
    132140        }
    133141
     
    149157     * Check if the current option is handled by a profile.
    150158     *
    151      * @param int    $siteId
     159     * @param int $siteId
    152160     * @param string $optionName
    153161     *
     
    157165    {
    158166        $profileId = $this->findProfileId($siteId);
    159         $permission = $this->profileConfigurationRepository->findSanitizedPermission($profileId, $optionName);
    160 
    161         if (NextADInt_Multisite_Configuration_Service::EDITABLE > $permission) {
     167        $forcePermission = $this->profileConfigurationRepository->findSanitizedPermission($profileId, $optionName);
     168
     169        if (NextADInt_Multisite_Configuration_Service::EDITABLE > $forcePermission) {
    162170            return true;
    163171        }
     
    170178     * the sanitizer will create a new value from the default value. This value will be persist, requested and returned.
    171179     *
    172      * @param int    $siteId
     180     * @param int $siteId
    173181     * @param string $optionName
    174182     * @param array $option
     
    176184     * @return bool|mixed|null|string
    177185     */
    178     public function getDefaultValue($siteId, $optionName, $option)
     186    function getDefaultValue($siteId, $optionName, $option)
    179187    {
    180188        // gh-#127: PHP 7.4 compatibility; warning if $option is not an array but null
     
    199207    /**
    200208     * This method should not be called by the outside (expect for the migration of the encrypted passwords).
    201      * Read the value for option $optionName and site/blog $blogId.
    202      *
    203      * @param int    $siteId
     209     * Read the value for option $optionName and site $siteId.
     210     *
     211     * @param int $siteId
    204212     * @param string $optionName
    205213     *
     
    211219
    212220        if (is_multisite()) {
    213             return get_blog_option($siteId, $name, false);
    214         }
    215 
    216         return get_option($name, false);
     221            $r =  get_blog_option($siteId, $name, null);
     222            return $r;
     223        }
     224
     225        return get_option($name, null);
    217226    }
    218227
     
    221230     * Moreover this method sanitize, encrypt etc. the value.
    222231     *
    223      * @param int    $siteSiteId
     232     * @param int $siteId
    224233     * @param string $optionName
    225234     * @param string $optionValue
     
    227236     * @return string $optionValue return the sanitized value
    228237     */
    229     public function persistSanitizedValue($siteSiteId, $optionName, $optionValue)
     238    public function persistSanitizedValue($siteId, $optionName, $optionValue)
    230239    {
    231240        if (self::PROFILE_ID === $optionName) {
     
    246255        }
    247256
    248         return $this->persist($siteSiteId, $optionName, $optionValue);
     257        return $this->persist($siteId, $optionName, $optionValue);
    249258    }
    250259
     
    253262     * Write the value $optionValue for option $optionName and blog/site $blogId.
    254263     *
    255      * @param int    $siteId
     264     * @param int $siteId
    256265     * @param string $optionName
    257266     * @param mixed $optionValue
     
    275284            }
    276285
    277         // Singlesite
     286            // Singlesite
    278287        } else {
    279288            $optionExists = $this->doesOptionExist($optionName);
     
    304313     * @return bool
    305314     */
    306     protected function createOption($optionName, $optionValue, $siteId = null) {
     315    protected function createOption($optionName, $optionValue, $siteId = null)
     316    {
    307317
    308318        // Create Multi Site option
    309319        if ($siteId) {
    310320            $success = add_blog_option($siteId, $optionName, $optionValue);
    311         }
    312         // Create Single Site option
     321        } // Create Single Site option
    313322        else {
    314323            $success = add_option($optionName, $optionValue, false);
     
    333342     * @return bool
    334343     */
    335     protected function updateOption($optionName, $optionValue, $siteId = null) {
     344    protected function updateOption($optionName, $optionValue, $siteId = null)
     345    {
    336346
    337347        // Update Multi Site option
    338348        if ($siteId) {
    339349            $success = update_blog_option($siteId, $optionName, $optionValue);
    340         }
    341         // Update Single Site option
     350        } // Update Single Site option
    342351        else {
    343352            $success = update_option($optionName, $optionValue, false);
     
    361370     * @return bool
    362371     */
    363     protected function doesOptionExist($optionName, $siteId = null) {
     372    protected function doesOptionExist($optionName, $siteId = null)
     373    {
    364374
    365375        if ($siteId) {
     
    392402
    393403    /**
    394      * Get id of the associated profile of this blog $blogId.
     404     * Get id of the associated profile of this site's $siteId.
     405     * To make it more performant, the linked profile is cached.
    395406     *
    396407     * @param int $siteId
     
    400411    public function findProfileId($siteId)
    401412    {
    402         $profileId = $this->findRawValue($siteId, self::PROFILE_ID);
    403 
    404         if (false === $profileId) {
    405             $profileId = $this->defaultProfileRepository->findProfileId();
    406         }
    407 
    408         return $profileId;
     413        $key = "K-" . $siteId;
     414
     415        if (!isset($this->siteToProfileCache[$key])) {
     416            $profileId = $this->findRawValue($siteId, self::PROFILE_ID);
     417
     418            // no profile for this site has been specified, so find the default profile
     419            if (!is_numeric($profileId)) {
     420                $profileId = $this->defaultProfileRepository->findProfileId();
     421            }
     422
     423            $this->siteToProfileCache[$key] = (int)$profileId;
     424        }
     425
     426        return $this->siteToProfileCache[$key];
    409427    }
    410428
     
    412430     * Set id of the associated profile of this blog $blogId.
    413431     *
    414      * @param int    $siteId
     432     * @param int $siteId
    415433     * @param string $profileId
    416434     *
     
    425443     * Delete the associated of the profile with a blog $siteId.
    426444     *
    427      * @param int    $siteId
     445     * @param int $siteId
    428446     * @param string $profileId
    429447     *
     
    439457     * Delete an option value.
    440458     *
    441      * @param int   $siteId
     459     * @param int $siteId
    442460     * @param string $optionName
    443461     *
     
    519537     * Get the option permission for the profile and the option.
    520538     *
    521      * @param int    $profileId
     539     * @param int $profileId
    522540     * @param string $optionName
    523541     *
     
    530548
    531549    /**
    532      * @param int    $profileId
    533      * @param string $optionName
    534      * @param int    $optionPermission between [0,3]
     550     * @param int $profileId
     551     * @param string $optionName
     552     * @param int $optionPermission between [0,3]
    535553     *
    536554     * @return bool
  • next-active-directory-integration/trunk/classes/Multisite/Configuration/Persistence/ConfigurationRepository.php

    r1608780 r2513920  
    1919     * Find the value of the given option
    2020     *
    21      * @param int    $siteId
     21     * @param int    $id
    2222     * @param string $optionName
    2323     *
    2424     * @return mixed
    2525     */
    26     public function findSanitizedValue($siteId, $optionName);
     26    public function findSanitizedValue($id, $optionName);
    2727
    2828    /**
  • next-active-directory-integration/trunk/classes/Multisite/Configuration/Persistence/DefaultProfileRepository.php

    r1541870 r2513920  
    2929        $profileId = get_site_option($name, false);
    3030
    31         return (false === $profileId) ? -1 : $profileId;
     31        return (false === $profileId) ? -1 : (int)$profileId;
    3232    }
    3333
  • next-active-directory-integration/trunk/classes/Multisite/Configuration/Persistence/ProfileConfigurationRepository.php

    r1756617 r2513920  
    6767     * Get the option $optionName for the profile $profileId.
    6868     *
    69      * @param int    $profileSiteId
     69     * @param int    $profileId
    7070     * @param string $optionName
    7171     *
    7272     * @return object
    7373     */
    74     public function findSanitizedValue($profileSiteId, $optionName)
    75     {
    76         $value = $this->findRawValue($profileSiteId, $optionName);
     74    public function findSanitizedValue($profileId, $optionName)
     75    {
     76        $value = $this->findRawValue($profileId, $optionName);
    7777        $optionMetadata = $this->optionProvider->get($optionName);
    7878
    7979        if (false === $value) {
    80             $optionValue = $this->getDefaultValue($profileSiteId, $optionName, $optionMetadata);
     80            $optionValue = $this->getDefaultValue($profileId, $optionName, $optionMetadata);
    8181        }
    8282
  • next-active-directory-integration/trunk/classes/Multisite/Configuration/Service.php

    r2331595 r2513920  
    99
    1010/**
    11  * Multisite_Configuraiton_Service returns the value for an option name.
     11 * Multisite_Configuration_Service returns the value for an option name.
    1212 *
    13  * Multisite_Configuraiton_Service return the option value depending on the WordPress installation (single/multi side), profile settings and blog settings.
     13 * Multisite_Configuration_Service return the option value depending on the WordPress installation (single/multi side), profile settings and blog settings.
    1414 *
    1515 * @author Tobias Hellmann <[email protected]>
     
    5353    /* @var array */
    5454    private $cache = array();
    55 
    5655
    5756    /**
     
    9695     *
    9796     * @param string   $optionName
    98      * @param int|null $blogId if null, the current blog is used
     97     * @param int|null $siteId if null, the current blog is used
    9998     *
    10099     * @return mixed
    101100     */
    102     public function getOptionValue($optionName, $blogId = null)
    103     {
    104         $option = $this->getOption($optionName, $blogId);
     101    public function getOptionValue($optionName, $siteId = null)
     102    {
     103        $option = $this->getOption($optionName, $siteId);
    105104
    106105        return NextADInt_Core_Util_ArrayUtil::get('option_value', $option);
     
    108107
    109108    /**
    110      * Get the option hashmap with keys 'option_value', 'option_name', 'option_permission' for the option $optionName of blog $blogId.
    111      * If $blogId is null, then the current blog will be used.
     109     * Get the option hashmap with keys 'option_value', 'option_name', 'option_permission' for the option $optionName of site $siteId.
    112110     *
    113111     * @param string   $optionName name of option to lookup
    114      * @param int|null $blogId if null, the current blog is used
     112     * @param int|null $siteId if null, the current blog is used
    115113     *
    116114     * @return array
    117115     */
    118     public function getOption($optionName, $blogId = null)
    119     {
    120         if ($blogId === null) {
    121             $blogId = get_current_blog_id();
    122         }
    123 
    124         if (isset($this->cache[$blogId][$optionName]) && is_array($this->cache[$blogId][$optionName])) {
    125             return $this->cache[$blogId][$optionName];
    126         }
    127 
    128         $blogOptionValue = $this->blogConfigurationRepository->findSanitizedValue($blogId, $optionName);
    129         $profileId = $this->blogConfigurationRepository->findProfileId($blogId);
     116    public function getOption($optionName, $siteId = null)
     117    {
     118        if ($siteId === null) {
     119            $siteId = get_current_blog_id();
     120        }
     121
     122        if (isset($this->cache[$siteId][$optionName]) && is_array($this->cache[$siteId][$optionName])) {
     123            return $this->cache[$siteId][$optionName];
     124        }
     125
     126        $blogOptionValue = $this->blogConfigurationRepository->findSanitizedValue($siteId, $optionName);
     127
     128        $profileId = $this->blogConfigurationRepository->findProfileId($siteId);
     129
    130130        $profileHasLinkedDomain = false;
    131131
    132132        if ($profileId != null) {
    133             $profileDomainSid = $this->getProfileOptionValue(NextADInt_Adi_Configuration_Options::DOMAIN_SID, $blogId);
     133            $profileDomainSid = $this->getProfileOptionValue(NextADInt_Adi_Configuration_Options::DOMAIN_SID, $siteId);
    134134
    135135            if (!empty($profileDomainSid)) {
     
    138138        }
    139139
    140         $profileOptionValue = $this->getProfileOptionValue($optionName, $blogId);
     140        $profileOptionValue = $this->getProfileOptionValue($optionName, $siteId);
    141141        $permission = $this->getPermission($optionName, $profileId);
    142142
     
    161161        );
    162162
    163         $this->cache[$blogId][$optionName] = $optionArray;
     163        $this->cache[$siteId][$optionName] = $optionArray;
    164164
    165165        return $optionArray;
     
    171171     * Do not call this method from the outside.
    172172     *
    173      * @param int|null $blogId
     173     * @param int|null $siteId
    174174     * @param string   $optionName
    175175     *
    176176     * @return null|array null if singlesite installation
    177177     */
    178     public function getProfileOptionValue($optionName, $blogId = null)
     178    function getProfileOptionValue($optionName, $siteId = null)
    179179    {
    180180        if (!is_multisite()) {
     
    182182        }
    183183
    184         $profileId = $this->blogConfigurationRepository->findProfileId($blogId);
     184        $profileId = $this->blogConfigurationRepository->findProfileId($siteId);
    185185        $profileOption = $this->profileConfigurationRepository->findSanitizedValue($profileId, $optionName);
    186186
     
    197197     * @param mixed $blogOptionValue
    198198     *
    199      * @return mixed $blogOpotionValue if $permission is EDITABLE, otherwise $profileOptionValue
     199     * @return mixed $blogOptionValue if $permission is EDITABLE, otherwise $profileOptionValue
    200200     */
    201201    protected function getValue($permission, $profileOptionValue, $blogOptionValue)
     
    229229
    230230    /**
    231      * Find all options for the current site
     231     * Find all options for the current site.
     232     * It merges the default profile options with its overriden settings fo the current site.
     233     *
    232234     * @return array|mixed
    233235     */
    234236    public function getAllOptions()
    235237    {
     238        $siteId = get_current_blog_id();
     239
     240
    236241        $allOptionNames = $this->blogConfigurationRepository->getAllOptionNames();
    237         $profileId = $this->blogConfigurationRepository->findProfileId(get_current_blog_id());
    238 
    239         $options = array();
     242        $profileId = $this->blogConfigurationRepository->findProfileId($siteId);
    240243
    241244        foreach ($allOptionNames as $name) {
    242             $buffer = $this->getOption($name);
     245            $buffer = $this->getOption($name, $siteId);
    243246
    244247            if ($name == "additional_user_attributes") { //TODO find better solution
     
    334337            NextADInt_Adi_Configuration_Options::VERIFICATION_USERNAME,
    335338            NextADInt_Adi_Configuration_Options::VERIFICATION_PASSWORD,
    336             NextADInt_Adi_Configuration_Options::ENCRYPTION
     339            NextADInt_Adi_Configuration_Options::ENCRYPTION,
     340            NextADInt_Adi_Configuration_Options::ADDITIONAL_DOMAIN_SIDS
    337341        ); //TODO move somewhere else
    338342
  • next-active-directory-integration/trunk/classes/Multisite/Ui/BlogConfigurationPage.php

    r2331595 r2513920  
    4545    private $actionMapping
    4646        = array(
    47             self::SUB_ACTION_GENERATE_AUTHCODE     => self::SUB_ACTION_GENERATE_AUTHCODE,
     47            self::SUB_ACTION_GENERATE_AUTHCODE => self::SUB_ACTION_GENERATE_AUTHCODE,
    4848            self::SUB_ACTION_GET_ALL_OPTION_VALUES => self::SUB_ACTION_GET_ALL_OPTION_VALUES,
    4949            self::SUB_ACTION_PERSIST_OPTION_VALUES => self::SUB_ACTION_PERSIST_OPTION_VALUES,
    50             self::SUB_ACTION_VERIFY_AD_CONNECTION  => self::SUB_ACTION_VERIFY_AD_CONNECTION,
    51         );
    52 
    53     /**
    54      * @param NextADInt_Multisite_View_TwigContainer             $twigContainer
     50            self::SUB_ACTION_VERIFY_AD_CONNECTION => self::SUB_ACTION_VERIFY_AD_CONNECTION,
     51        );
     52
     53    /**
     54     * @param NextADInt_Multisite_View_TwigContainer $twigContainer
    5555     * @param NextADInt_Multisite_Ui_BlogConfigurationController $blogConfigurationConfigurationControllerController
    5656     */
    5757    public function __construct(NextADInt_Multisite_View_TwigContainer $twigContainer,
    5858                                NextADInt_Multisite_Ui_BlogConfigurationController $blogConfigurationConfigurationControllerController
    59     ) {
     59    )
     60    {
    6061        parent::__construct($twigContainer);
    6162
     
    9899    public function renderAdmin()
    99100    {
    100         // translate twig text
    101         $i18n = array(
    102             'title' => __('Next Active Directory Integration Blog Configuration', 'next-active-directory-integration'),
    103             'regenerateAuthCode' => __('Regenerate Auth Code', 'next-active-directory-integration'),
    104             'securityGroup' => __('Security group', 'next-active-directory-integration'),
    105             'wordpressRole' => __('WordPress role', 'next-active-directory-integration'),
    106             'selectRole' => __('Please select a role', 'next-active-directory-integration'),
    107             'verify' => __('Verify', 'next-active-directory-integration'),
    108             'adAttributes' => __('AD Attributes', 'next-active-directory-integration'),
    109             'dataType' => __('Data Type', 'next-active-directory-integration'),
    110             'wordpressAttribute' => __('WordPress Attribute', 'next-active-directory-integration'),
    111             'description' => __('Description', 'next-active-directory-integration'),
    112             'viewInUserProfile' => __('View in User Profile', 'next-active-directory-integration'),
    113             'syncToAd' => __('Sync to AD', 'next-active-directory-integration'),
    114             'overwriteWithEmptyValue' => __('Overwrite with empty value', 'next-active-directory-integration'),
    115             'wantToRegenerateAuthCode' => __('Do you really want to regenerate a new AuthCode?', 'next-active-directory-integration'),
    116             'wordPressIsConnectedToDomain' => __('WordPress Site is currently connected to Domain: ', 'next-active-directory-integration'),
    117             'domainConnectionVerificationSuccessful' => __('Verification successful! WordPress site is now connected to Domain: ', 'next-active-directory-integration'),
    118             'verificationSuccessful' => __('Verification successful!', 'next-active-directory-integration'),
    119             'domainConnectionVerificationFailed' => __('Verification failed! Please check your logfile for further information.', 'next-active-directory-integration'),
    120             'managePermissions' => __('Manage Permissions', 'next-active-directory-integration'),
    121             'noOptionsExists' => __('No options exists', 'next-active-directory-integration'),
    122             'pleaseWait' => __('Please wait...', 'next-active-directory-integration'),
    123             'save' => __('Save', 'next-active-directory-integration'),
    124             'haveToVerifyDomainConnection' => __('You have to verify the connection to the AD before saving.', 'next-active-directory-integration'),
    125             'errorWhileSaving' => __('An error occurred while saving the configuration.', 'next-active-directory-integration'),
    126             'savingSuccessful' => __('The configuration has been saved successfully.', 'next-active-directory-integration')
    127         );
     101        // translate twig text
     102        $i18n = array(
     103            'title' => __('Next Active Directory Integration Blog Configuration', 'next-active-directory-integration'),
     104            'regenerateAuthCode' => __('Regenerate Auth Code', 'next-active-directory-integration'),
     105            'securityGroup' => __('Security group', 'next-active-directory-integration'),
     106            'wordpressRole' => __('WordPress role', 'next-active-directory-integration'),
     107            'selectRole' => __('Please select a role', 'next-active-directory-integration'),
     108            'verify' => __('Verify', 'next-active-directory-integration'),
     109            'adAttributes' => __('AD Attributes', 'next-active-directory-integration'),
     110            'dataType' => __('Data Type', 'next-active-directory-integration'),
     111            'wordpressAttribute' => __('WordPress Attribute', 'next-active-directory-integration'),
     112            'description' => __('Description', 'next-active-directory-integration'),
     113            'viewInUserProfile' => __('View in User Profile', 'next-active-directory-integration'),
     114            'syncToAd' => __('Sync to AD', 'next-active-directory-integration'),
     115            'overwriteWithEmptyValue' => __('Overwrite with empty value', 'next-active-directory-integration'),
     116            'wantToRegenerateAuthCode' => __('Do you really want to regenerate a new AuthCode?', 'next-active-directory-integration'),
     117            'wordPressIsConnectedToDomain' => __('WordPress Site is currently connected to Domain: ', 'next-active-directory-integration'),
     118            'domainConnectionVerificationSuccessful' => __('Verification successful! WordPress site is now connected to Domain: ', 'next-active-directory-integration'),
     119            'verificationSuccessful' => __('Verification successful!', 'next-active-directory-integration'),
     120            'domainConnectionVerificationFailed' => __('Verification failed! Please check your logfile for further information.', 'next-active-directory-integration'),
     121            'managePermissions' => __('Manage Permissions', 'next-active-directory-integration'),
     122            'noOptionsExists' => __('No options exists', 'next-active-directory-integration'),
     123            'pleaseWait' => __('Please wait...', 'next-active-directory-integration'),
     124            'save' => __('Save', 'next-active-directory-integration'),
     125            'haveToVerifyDomainConnection' => __('You have to verify the connection to the AD before saving.', 'next-active-directory-integration'),
     126            'errorWhileSaving' => __('An error occurred while saving the configuration.', 'next-active-directory-integration'),
     127            'savingSuccessful' => __('The configuration has been saved successfully.', 'next-active-directory-integration')
     128        );
    128129        $i18n = NextADInt_Core_Util_EscapeUtil::escapeHarmfulHtml($i18n);
    129130
     
    131132            self::TEMPLATE, array(
    132133                'nonce' => wp_create_nonce(self::NONCE),// create nonce for security
    133                 'i18n' => $i18n
     134                'i18n' => $i18n
    134135            )
    135136        );
     
    190191            'next_ad_int_blog_options_controller_security', NEXT_AD_INT_URL .
    191192            '/js/app/blog-options/controllers/security.controller.js', array(), self::VERSION_BLOG_OPTIONS_JS
     193        );
     194        wp_enqueue_script(
     195            'next_ad_int_blog_options_controller_sso', NEXT_AD_INT_URL .
     196            '/js/app/blog-options/controllers/sso.controller.js', array(), self::VERSION_BLOG_OPTIONS_JS
    192197        );
    193198        wp_enqueue_script(
     
    355360
    356361        return array(
    357             'options'        => $data,
     362            'options' => $data,
    358363            'ldapAttributes' => NextADInt_Ldap_Attribute_Description::findAll(),
    359             'dataTypes'      => NextADInt_Ldap_Attribute_Repository::findAllAttributeTypes(),
    360             'wpRoles'        => NextADInt_Adi_Role_Manager::getRoles(),
     364            'dataTypes' => NextADInt_Ldap_Attribute_Repository::findAllAttributeTypes(),
     365            'wpRoles' => NextADInt_Adi_Role_Manager::getRoles(),
    361366        );
    362367    }
     
    390395
    391396        // only call verifyInternal if no validation errors were found (warnings are excluded)
    392         if(!$validation->containsErrors()) {
     397        if (!$validation->containsErrors()) {
    393398            $connection = $this->verifyInternal($data);
    394399        }
     
    405410     *
    406411     * @param array $data
    407      * @param null  $profileId
     412     * @param null $profileId
    408413     *
    409414     * @return array
     
    421426        }
    422427
    423         $domainSid = NextADInt_Core_Util_StringUtil::objectSidToDomainSid($objectSid);
     428        $domainSid = $objectSid->getDomainPartAsSid()->getFormatted();
    424429        $domainSidData = $this->prepareDomainSid($domainSid);
    425430
     
    430435        $netBiosName = $this->twigContainer->findActiveDirectoryNetBiosName($data);
    431436
    432         $netBiosData = array();
    433         if($netBiosName) {
     437        $netBiosData = array();
     438        if ($netBiosName) {
    434439            $netBiosData = $this->prepareNetBiosName($netBiosName);
    435440            $this->persistNetBiosName($netBiosData, $profileId);
     
    457462    }
    458463
    459     protected function prepareNetBiosName($netBiosName) {
     464    protected function prepareNetBiosName($netBiosName)
     465    {
    460466        if (is_string($netBiosName) && $netBiosName !== '') {
    461467            return $this->getNetBiosNameForPersistence($netBiosName);
     
    477483    }
    478484
    479     protected function getNetBiosNameForPersistence($netBiosName) {
     485    protected function getNetBiosNameForPersistence($netBiosName)
     486    {
    480487        return array("netbios_name" => $netBiosName);
    481488    }
     
    512519        $validation = $this->validate($data);
    513520        // only call saveBlogOptions if no validation errors are present (warnings are excluded)
    514         if(!$validation->containsErrors()) {
     521        if (!$validation->containsErrors()) {
    515522            $connection = $this->blogConfigurationController->saveBlogOptions($data);
    516523        }
     
    686693            // PERMISSIONS
    687694            $disallowedRoleMessage = __('The role super admin can only be set inside a profile.', 'next-active-directory-integration');
    688             $invalidRoleMessage = __('At least one security group is associated with a non existing WordPress role. Please select an existing role for the group.', 'next-active-directory-integration');
     695            $invalidRoleMessage = __('At least one security group is associated with a non existing WordPress role. Please select an existing role for the group.', 'next-active-directory-integration');
    689696            $disallowedRoleRule = new NextADInt_Multisite_Validator_Rule_DisallowInvalidWordPressRoles(array($disallowedRoleMessage, $invalidRoleMessage));
    690697            $validator->addRule(NextADInt_Adi_Configuration_Options::ROLE_EQUIVALENT_GROUPS, $disallowedRoleRule);
     
    791798
    792799        $domainControllerMessage = __('Domain Controller cannot be empty.', 'next-active-directory-integration');
    793         $domainControllerRule = new NextADInt_Multisite_Validator_Rule_NotEmptyOrWhitespace($domainControllerMessage);
    794         $validator->addRule(NextADInt_Adi_Configuration_Options::DOMAIN_CONTROLLERS, $domainControllerRule);
     800        $domainControllerRule = new NextADInt_Multisite_Validator_Rule_NotEmptyOrWhitespace($domainControllerMessage);
     801        $validator->addRule(NextADInt_Adi_Configuration_Options::DOMAIN_CONTROLLERS, $domainControllerRule);
    795802
    796803        return $validator;
  • next-active-directory-integration/trunk/classes/Multisite/Ui/ProfileConfigurationPage.php

    r2331595 r2513920  
    4545    /** @var array map the given subActions to the corresponding methods */
    4646    private $actionMapping = array(
    47         self::SUB_ACTION_SAVE_PROFILE                  => self::SUB_ACTION_SAVE_PROFILE,
    48         self::SUB_ACTION_REMOVE_PROFILE                => self::SUB_ACTION_REMOVE_PROFILE,
    49         self::SUB_ACTION_GET_PROFILE_OPTION_VALUES     => self::SUB_ACTION_GET_PROFILE_OPTION_VALUES,
     47        self::SUB_ACTION_SAVE_PROFILE => self::SUB_ACTION_SAVE_PROFILE,
     48        self::SUB_ACTION_REMOVE_PROFILE => self::SUB_ACTION_REMOVE_PROFILE,
     49        self::SUB_ACTION_GET_PROFILE_OPTION_VALUES => self::SUB_ACTION_GET_PROFILE_OPTION_VALUES,
    5050        self::SUB_ACTION_PERSIST_PROFILE_OPTION_VALUES => self::SUB_ACTION_PERSIST_PROFILE_OPTION_VALUES,
    51         self::SUB_ACTION_LOAD_PROFILES                 => self::SUB_ACTION_LOAD_PROFILES,
    52         self::SUB_ACTION_GENERATE_AUTHCODE             => self::SUB_ACTION_GENERATE_AUTHCODE,
    53         parent::SUB_ACTION_VERIFY_AD_CONNECTION        => parent::SUB_ACTION_VERIFY_AD_CONNECTION,
     51        self::SUB_ACTION_LOAD_PROFILES => self::SUB_ACTION_LOAD_PROFILES,
     52        self::SUB_ACTION_GENERATE_AUTHCODE => self::SUB_ACTION_GENERATE_AUTHCODE,
     53        parent::SUB_ACTION_VERIFY_AD_CONNECTION => parent::SUB_ACTION_VERIFY_AD_CONNECTION,
    5454    );
    5555
    5656    /**
    57      * @param NextADInt_Multisite_View_TwigContainer                $twigContainer
    58      * @param NextADInt_Multisite_Ui_BlogConfigurationController    $blogConfigurationController
     57     * @param NextADInt_Multisite_View_TwigContainer $twigContainer
     58     * @param NextADInt_Multisite_Ui_BlogConfigurationController $blogConfigurationController
    5959     * @param NextADInt_Multisite_Ui_ProfileConfigurationController $profileConfigurationController
    60      * @param NextADInt_Multisite_Ui_ProfileController              $profileController
    61      * @param NextADInt_Multisite_Configuration_Service             $configurationService
     60     * @param NextADInt_Multisite_Ui_ProfileController $profileController
     61     * @param NextADInt_Multisite_Configuration_Service $configurationService
    6262     */
    6363    public function __construct(NextADInt_Multisite_View_TwigContainer $twigContainer,
     
    6666                                NextADInt_Multisite_Ui_ProfileController $profileController,
    6767                                NextADInt_Multisite_Configuration_Service $configurationService
    68     ) {
     68    )
     69    {
    6970        parent::__construct($twigContainer, $blogConfigurationController);
    7071
     
    111112        $relativeUrl = add_query_arg('page', NextADInt_Multisite_Ui_BlogProfileRelationshipPage::buildSlug());
    112113
    113         // translate twig text
    114         $i18n = array(
    115             'warningDiscardChanges' => __('The current profile contains unsaved changes. Are you sure you want to continue?', 'next-active-directory-integration'),
    116             'deleteProfileAssociatedSites' => __('The current profile is associated with the following sites:', 'next-active-directory-integration'),
    117             'deleteProfileAssociated' => __('The current profile is associated with {{ associations.length }} sites. Are you sure you want to delete this profile?', 'next-active-directory-integration'),
    118             'assignNewProfile' => __('Assign to profile:', 'next-active-directory-integration'),
    119             'newProfile' => __('New Profile', 'next-active-directory-integration'),
    120             'none' => __('None', 'next-active-directory-integration'),
    121             'configureSettingsForProfile' => __('Configure Settings for Profile : ', 'next-active-directory-integration'),
    122             'createNewProfile' => __('Create new profile', 'next-active-directory-integration'),
    123             'deleteProfile' => __('Delete profile', 'next-active-directory-integration'),
    124             'viewAssociatedProfiles' => __('View associated profiles', 'next-active-directory-integration'),
    125             'regenerateAuthCode' => __('Regenerate Auth Code', 'next-active-directory-integration'),
    126             'securityGroup' => __('Security group', 'next-active-directory-integration'),
    127             'wordpressRole' => __('WordPress role', 'next-active-directory-integration'),
    128             'selectRole' => __('Please select a role', 'next-active-directory-integration'),
    129             'verify' => __('Verify', 'next-active-directory-integration'),
    130             'adAttributes' => __('AD Attributes', 'next-active-directory-integration'),
    131             'dataType' => __('Data Type', 'next-active-directory-integration'),
    132             'wordpressAttribute' => __('WordPress Attribute', 'next-active-directory-integration'),
    133             'description' => __('Description', 'next-active-directory-integration'),
    134             'viewInUserProfile' => __('View in User Profile', 'next-active-directory-integration'),
    135             'syncToAd' => __('Sync to AD', 'next-active-directory-integration'),
    136             'overwriteWithEmptyValue' => __('Overwrite with empty value', 'next-active-directory-integration'),
    137             'wantToRegenerateAuthCode' => __('Do you really want to regenerate a new AuthCode?', 'next-active-directory-integration'),
    138             'wordPressIsConnectedToDomain' => __('WordPress Site is currently connected to Domain: ', 'next-active-directory-integration'),
    139             'domainConnectionVerificationSuccessful' => __('Verification successful! WordPress site is now connected to Domain: ', 'next-active-directory-integration'),
    140             'verificationSuccessful' => __('Verification successful!', 'next-active-directory-integration'),
    141             'domainConnectionVerificationFailed' => __('Verification failed! Please check your logfile for further information.', 'next-active-directory-integration'),
    142             'managePermissions' => __('Manage Permissions', 'next-active-directory-integration'),
    143             'noOptionsExists' => __('No options exists', 'next-active-directory-integration'),
    144             'pleaseWait' => __('Please wait...', 'next-active-directory-integration'),
    145             'save' => __('Save', 'next-active-directory-integration'),
    146             'haveToVerifyDomainConnection' => __('You have to verify the connection to the AD before saving.', 'next-active-directory-integration'),
    147             'errorWhileSaving' => __('An error occurred while saving the configuration.', 'next-active-directory-integration'),
    148             'savingSuccessful' => __('The configuration has been saved successfully.', 'next-active-directory-integration')
    149         );
     114        // translate twig text
     115        $i18n = array(
     116            'warningDiscardChanges' => __('The current profile contains unsaved changes. Are you sure you want to continue?', 'next-active-directory-integration'),
     117            'deleteProfileAssociatedSites' => __('The current profile is associated with the following sites:', 'next-active-directory-integration'),
     118            'deleteProfileAssociated' => __('The current profile is associated with {{ associations.length }} sites. Are you sure you want to delete this profile?', 'next-active-directory-integration'),
     119            'assignNewProfile' => __('Assign to profile:', 'next-active-directory-integration'),
     120            'newProfile' => __('New Profile', 'next-active-directory-integration'),
     121            'none' => __('None', 'next-active-directory-integration'),
     122            'configureSettingsForProfile' => __('Configure Settings for Profile : ', 'next-active-directory-integration'),
     123            'createNewProfile' => __('Create new profile', 'next-active-directory-integration'),
     124            'deleteProfile' => __('Delete profile', 'next-active-directory-integration'),
     125            'viewAssociatedProfiles' => __('View associated profiles', 'next-active-directory-integration'),
     126            'regenerateAuthCode' => __('Regenerate Auth Code', 'next-active-directory-integration'),
     127            'securityGroup' => __('Security group', 'next-active-directory-integration'),
     128            'wordpressRole' => __('WordPress role', 'next-active-directory-integration'),
     129            'selectRole' => __('Please select a role', 'next-active-directory-integration'),
     130            'verify' => __('Verify', 'next-active-directory-integration'),
     131            'adAttributes' => __('AD Attributes', 'next-active-directory-integration'),
     132            'dataType' => __('Data Type', 'next-active-directory-integration'),
     133            'wordpressAttribute' => __('WordPress Attribute', 'next-active-directory-integration'),
     134            'description' => __('Description', 'next-active-directory-integration'),
     135            'viewInUserProfile' => __('View in User Profile', 'next-active-directory-integration'),
     136            'syncToAd' => __('Sync to AD', 'next-active-directory-integration'),
     137            'overwriteWithEmptyValue' => __('Overwrite with empty value', 'next-active-directory-integration'),
     138            'wantToRegenerateAuthCode' => __('Do you really want to regenerate a new AuthCode?', 'next-active-directory-integration'),
     139            'wordPressIsConnectedToDomain' => __('WordPress Site is currently connected to Domain: ', 'next-active-directory-integration'),
     140            'domainConnectionVerificationSuccessful' => __('Verification successful! WordPress site is now connected to Domain: ', 'next-active-directory-integration'),
     141            'verificationSuccessful' => __('Verification successful!', 'next-active-directory-integration'),
     142            'domainConnectionVerificationFailed' => __('Verification failed! Please check your logfile for further information.', 'next-active-directory-integration'),
     143            'managePermissions' => __('Manage Permissions', 'next-active-directory-integration'),
     144            'noOptionsExists' => __('No options exists', 'next-active-directory-integration'),
     145            'pleaseWait' => __('Please wait...', 'next-active-directory-integration'),
     146            'save' => __('Save', 'next-active-directory-integration'),
     147            'haveToVerifyDomainConnection' => __('You have to verify the connection to the AD before saving.', 'next-active-directory-integration'),
     148            'errorWhileSaving' => __('An error occurred while saving the configuration.', 'next-active-directory-integration'),
     149            'savingSuccessful' => __('The configuration has been saved successfully.', 'next-active-directory-integration')
     150        );
    150151
    151152        $i18n = NextADInt_Core_Util_EscapeUtil::escapeHarmfulHtml($i18n);
     
    153154        $this->display(self::TEMPLATE, array(
    154155            'blog_profile_relationship_url' => $relativeUrl,
    155             'nonce'                         => wp_create_nonce(self::NONCE), //create nonce for security
    156             'blog_rel_nonce'                => wp_create_nonce(NextADInt_Multisite_Ui_BlogProfileRelationshipPage::NONCE),
    157             'i18n' => $i18n
     156            'nonce' => wp_create_nonce(self::NONCE), //create nonce for security
     157            'blog_rel_nonce' => wp_create_nonce(NextADInt_Multisite_Ui_BlogProfileRelationshipPage::NONCE),
     158            'i18n' => $i18n
    158159        ));
    159160    }
     
    207208            '/js/app/profile-options/controllers/security.controller.js',
    208209            array(), self::VERSION_PROFILE_CONFIGURATION_JS);
     210        wp_enqueue_script('next_ad_int_profile_options_controller_sso', NEXT_AD_INT_URL .
     211            '/js/app/profile-options/controllers/sso.controller.js',
     212            array(), self::VERSION_PROFILE_CONFIGURATION_JS);
    209213        wp_enqueue_script('next_ad_int_profile_options_controller_attributes', NEXT_AD_INT_URL .
    210214            '/js/app/profile-options/controllers/attributes.controller.js',
     
    301305        return array(
    302306            "domain_sid" => array(
    303                 "option_value"      => $domainSid,
     307                "option_value" => $domainSid,
    304308                "option_permission" => 3, //TODO revisit (default value to prevent saving errors)
    305309            ),
     
    396400    {
    397401        return array(
    398             'profiles'           => $this->profileController->findAll(),
     402            'profiles' => $this->profileController->findAll(),
    399403            'associatedProfiles' => $this->profileController->findAllProfileAssociations(),
    400404            'defaultProfileData' => $this->configuration->getProfileOptionsValues(-1),
    401             'ldapAttributes'     => NextADInt_Ldap_Attribute_Description::findAll(),
    402             'dataTypes'          => NextADInt_Ldap_Attribute_Repository::findAllAttributeTypes(),
    403             'permissionItems'    => $this->getPermission(),
    404             'wpRoles'        => NextADInt_Adi_Role_Manager::getRoles(),
     405            'ldapAttributes' => NextADInt_Ldap_Attribute_Description::findAll(),
     406            'dataTypes' => NextADInt_Ldap_Attribute_Repository::findAllAttributeTypes(),
     407            'permissionItems' => $this->getPermission(),
     408            'wpRoles' => NextADInt_Adi_Role_Manager::getRoles(),
    405409        );
    406410    }
     
    416420        $permissionItems = array(
    417421            0 => array(
    418                 "value"       => "0",
     422                "value" => "0",
    419423                "description" => __("Input field is invisible.", 'next-active-directory-integration'),
    420424            ),
    421425            1 => array(
    422                 "value"       => "1",
     426                "value" => "1",
    423427                "description" => __("Deactivated and option value not shown.", 'next-active-directory-integration'),
    424428            ),
    425429            2 => array(
    426                 "value"       => "2",
     430                "value" => "2",
    427431                "description" => __("Deactivated and option value shown.", 'next-active-directory-integration'),
    428432            ),
    429433            3 => array(
    430                 "value"       => "3",
     434                "value" => "3",
    431435                "description" => __("Blog admin sets the option value.", 'next-active-directory-integration'),
    432436            ),
     
    474478    }
    475479
    476     private function getErrorMessage($profileId, $profileName, $result) {
     480    private function getErrorMessage($profileId, $profileName, $result)
     481    {
    477482        $errorMessage = NextADInt_Core_Message::error(__('An error occurred while saving the configuration.', 'next-active-directory-integration'))->toArray();
    478483        $errorMessage['additionalInformation'] = array(
    479             'profileId'   => $profileId,
     484            'profileId' => $profileId,
    480485            'profileName' => $profileName,
    481486        );
     
    486491    }
    487492
    488     private function getPersistStatusMessage($profileId, $profileName, $persistStatusMessage, $validationResult) {
     493    private function getPersistStatusMessage($profileId, $profileName, $persistStatusMessage, $validationResult)
     494    {
    489495        $persistStatusMessage['additionalInformation'] = array(
    490             'profileId'   => $profileId,
     496            'profileId' => $profileId,
    491497            'profileName' => $profileName,
    492498        );
  • next-active-directory-integration/trunk/classes/Multisite/View/TwigContainer.php

    r1608780 r2513920  
    418418     * @param $data
    419419     *
    420      * @return bool
     420     * @return bool|ActiveDirectory_Sid
    421421     */
    422422    public function findActiveDirectoryDomainSid($data)
  • next-active-directory-integration/trunk/index.php

    r2331601 r2513920  
    44Plugin URI: https://www.active-directory-wp.com
    55Description: Enterprise-ready solution to authenticate, authorize and synchronize your Active Directory users to WordPress. Next Active Directory Authentication supports NTLM and Kerberos for Single Sign On.
    6 Version: 2.1.12
     6Version: 2.2.0
    77Author: active-directory-wp.com
    88Author URI: http://active-directory-wp.com
  • next-active-directory-integration/trunk/js/app/blog-options/controllers/environment.controller.js

    r2331595 r2513920  
    1111        $scope.permissionOptions = DataService.getPermissionOptions();
    1212        $scope.new_domain_controllers = '';
     13        $scope.new_additional_domain_sids = '';
    1314
    14         $scope.remove_domain_controllers = function (index) {
    15             $scope.option.domain_controllers = ListService.removeListItem(index, $scope.option.domain_controllers);
    16         };
     15        $scope.remove_domain_controllers = function (index) {
     16            $scope.option.domain_controllers = ListService.removeListItem(index, $scope.option.domain_controllers);
     17        };
     18
     19        $scope.remove_additional_domain_sids = function (index) {
     20            $scope.option.additional_domain_sids = ListService.removeListItem(index, $scope.option.additional_domain_sids);
     21        };
    1722
    1823        $scope.add_domain_controllers = function (newItem) {
     
    2025            $scope.new_domain_controllers = "";
    2126        };
     27
     28        $scope.add_additional_domain_sids = function (newItem) {
     29            $scope.option.additional_domain_sids = ListService.addListItem(newItem, $scope.option.additional_domain_sids);
     30            $scope.new_additional_domain_sids = "";
     31        };
    2232
    2333        $scope.$on('options', function (event, data) {
     
    3343                domain_sid: $valueHelper.findValue("domain_sid", data),
    3444                netbios_name: $valueHelper.findValue("netbios_name", data),
    35                 verification_status_message: ''
    36             };
     45                verification_status_message: '',
     46                additional_domain_sids: $valueHelper.findValue('additional_domain_sids', data, '').split(";")
     47            };
    3748
    3849            if ($valueHelper.findValue("domain_sid", data) == '') {
     
    5061                verification_password : $valueHelper.findPermission("verification_password", data),
    5162                domain_sid: $valueHelper.findPermission("domain_sid", data),
    52                 netbios_name: $valueHelper.findPermission("netbios_name", data)
     63                netbios_name: $valueHelper.findPermission("netbios_name", data),
     64                additional_domain_sids: $valueHelper.findPermission('additional_domain_sids', data)
    5365            };
    5466           
     
    6981                verification_password : $valueHelper.findMessage("verification_password", data),
    7082                domain_sid: $valueHelper.findMessage("domain_sid", data),
    71                 netbios_name: $valueHelper.findMessage("netbios_name", data)
     83                netbios_name: $valueHelper.findMessage("netbios_name", data),
     84                additional_domain_sids: $valueHelper.findMessage('additional_domain_sids', data)
    7285            };
    7386        });
     
    7588        $scope.getPreparedOptions = function () {
    7689            var data = DataService.cleanOptions($scope.option);
     90
    7791            data['domain_controllers'] = ListService.parseListArrayToString($scope.option.domain_controllers);
     92            data['additional_domain_sids'] = ListService.parseListArrayToString($scope.option.additional_domain_sids);
     93
    7894            return data;
    7995        };
     
    86102
    87103            // check if the input field is not empty
    88             if($scope.new_domain_controllers != '') {
     104            if ($scope.new_domain_controllers != '') {
    89105                // add the input field value to the list of objects to be saved
    90106                ListService.addListItem($scope.new_domain_controllers, $scope.option.domain_controllers);
    91107                $scope.new_domain_controllers = '';
    92108            }
     109
     110            if ($scope.new_additional_domain_sids != '') {
     111                // add the input field value to the list of objects to be saved
     112                ListService.addListItem($scope.new_additional_domain_sids, $scope.option.additional_domain_sids);
     113                $scope.new_additional_domain_sids = '';
     114            }
    93115
    94116            var data = {
     
    100122                base_dn: $scope.option.base_dn,
    101123                verification_username: $scope.option.verification_username,
    102                 verification_password: $scope.option.verification_password
    103         };
     124                verification_password: $scope.option.verification_password,
     125                additional_domain_sids: ListService.parseListArrayToString($scope.option.additional_domain_sids),
     126            };
    104127           
    105128            $http.post('admin-ajax.php', {
  • next-active-directory-integration/trunk/js/app/blog-options/controllers/security.controller.js

    r2069979 r2513920  
    2424        $scope.$on('options', function (event, data) {
    2525            $scope.option = {
    26                 sso: $valueHelper.findValue("sso", data),
    27                 sso_user: $valueHelper.findValue("sso_user", data),
    28                 sso_password: $valueHelper.findValue("sso_password", data),
    29                 sso_environment_variable: $valueHelper.findValue("sso_environment_variable", data),
    30                 sso_disable_for_xmlrpc: $valueHelper.findValue("sso_disable_for_xmlrpc", data),
    3126                enable_smartcard_user_login: $valueHelper.findValue("enable_smartcard_user_login", data),
    3227                custom_login_page_enabled: $valueHelper.findValue("custom_login_page_enabled", data),
     
    4540
    4641            $scope.permission = {
    47                 sso: $valueHelper.findPermission("sso", data),
    48                 sso_user: $valueHelper.findPermission("sso_user", data),
    49                 sso_password: $valueHelper.findPermission("sso_password", data),
    50                 sso_environment_variable: $valueHelper.findPermission("sso_environment_variable", data),
    51                 sso_disable_for_xmlrpc: $valueHelper.findPermission("sso_disable_for_xmlrpc", data),
    5242                enable_smartcard_user_login: $valueHelper.findPermission("enable_smartcard_user_login", data),
    5343                custom_login_page_enabled: $valueHelper.findPermission("custom_login_page_enabled", data),
     
    5949                from_email: $valueHelper.findPermission("from_email", data),
    6050                allow_xmlrpc_login: $valueHelper.findPermission("allow_xmlrpc_login", data),
    61                 verification_username : $valueHelper.findPermission("verification_username", data),
    62                 verification_password : $valueHelper.findPermission("verification_password", data)
    6351            };
    6452        });
     
    6654        $scope.$on('validation', function (event, data) {
    6755            $scope.messages = {
    68                 sso: $valueHelper.findMessage("sso", data),
    69                 sso_user: $valueHelper.findMessage("sso_user", data),
    70                 sso_password: $valueHelper.findMessage("sso_password", data),
    71                 sso_environment_variable: $valueHelper.findMessage("sso_environment_variable", data),
    7256                enable_smartcard_user_login: $valueHelper.findMessage("enable_smartcard_user_login", data),
    7357                custom_login_page_enabled: $valueHelper.findMessage("custom_login_page_enabled", data),
  • next-active-directory-integration/trunk/js/app/profile-options/controllers/environment.controller.js

    r2331595 r2513920  
    1414
    1515        $scope.new_domain_controllers = '';
     16        $scope.new_additional_domain_sids = '';
    1617
    1718        $scope.remove_domain_controllers = function (index) {
     
    1920        };
    2021
     22        $scope.remove_additional_domain_sids = function (index) {
     23            $scope.option.additional_domain_sids = ListService.removeListItem(index, $scope.option.additional_domain_sids);
     24        };
     25
    2126        $scope.add_domain_controllers = function (newItem) {
    2227            $scope.option.domain_controllers = ListService.addListItem(newItem, $scope.option.domain_controllers);
    2328            $scope.new_domain_controllers = "";
    2429        };
     30
     31        $scope.add_additional_domain_sids = function (newItem) {
     32            $scope.option.additional_domain_sids = ListService.addListItem(newItem, $scope.option.additional_domain_sids);
     33            $scope.new_additional_domain_sids = "";
     34        };
    2535
    2636        $scope.$on('options', function (event, data) {
     
    3646                domain_sid: $valueHelper.findValue("domain_sid", data),
    3747                netbios_name: $valueHelper.findValue("netbios_name", data),
    38                 verification_status_message: ''
    39             };
     48                verification_status_message: '',
     49                additional_domain_sids: $valueHelper.findValue('additional_domain_sids', data, '').split(";")
     50            };
    4051
    4152            if ($scope.option.domain_sid == '') {
     
    5566                verification_password : $valueHelper.findPermission("verification_password", data),
    5667                domain_sid: $valueHelper.findPermission("domain_sid", data),
    57                 netbios_name: $valueHelper.findPermission("netbios_name", data)
    58             };
     68                netbios_name: $valueHelper.findPermission("netbios_name", data),
     69                additional_domain_sids: $valueHelper.findPermission('additional_domain_sids', data)
     70            };
    5971           
    6072
     
    7587                verification_password : $valueHelper.findMessage("verification_password", data),
    7688                domain_sid: $valueHelper.findMessage("domain_sid", data),
    77                 netbios_name: $valueHelper.findValue("netbios_name", data)
     89                netbios_name: $valueHelper.findValue("netbios_name", data),
     90                additional_domain_sids: $valueHelper.findMessage('additional_domain_sids', data)
    7891            };
    7992        });
     
    8194        $scope.getPreparedOptions = function () {
    8295            var data = DataService.cleanOptions($scope.option);
     96
    8397            data['domain_controllers'] = ListService.parseListArrayToString($scope.option.domain_controllers);
     98            data['additional_domain_sids'] = ListService.parseListArrayToString($scope.option.additional_domain_sids);
     99
    84100            return data;
    85101        };
     
    98114            }
    99115
     116            if ($scope.new_additional_domain_sids != '') {
     117                // add the input field value to the list of objects to be saved
     118                ListService.addListItem($scope.new_additional_domain_sids, $scope.option.additional_domain_sids);
     119                $scope.new_additional_domain_sids = '';
     120            }
     121
    100122            var data = {
    101123                domain_controllers: ListService.parseListArrayToString($scope.option.domain_controllers),
     
    107129                verification_username: $scope.option.verification_username,
    108130                verification_password: $scope.option.verification_password,
     131                additional_domain_sids: ListService.parseListArrayToString($scope.option.additional_domain_sids),
    109132                profile: $scope.activeProfile.profileId
    110133            };
  • next-active-directory-integration/trunk/js/app/profile-options/controllers/security.controller.js

    r2069979 r2513920  
    2626        $scope.$on('options', function (event, data) {
    2727            $scope.option = {
    28                 sso: $valueHelper.findValue("sso", data),
    29                 sso_user: $valueHelper.findValue("sso_user", data),
    30                 sso_password: $valueHelper.findValue("sso_password", data),
    31                 sso_environment_variable: $valueHelper.findValue("sso_environment_variable", data),
    32                 sso_disable_for_xmlrpc: $valueHelper.findValue("sso_disable_for_xmlrpc", data),
    3328                enable_smartcard_user_login: $valueHelper.findValue("enable_smartcard_user_login", data),
    3429                custom_login_page_enabled: $valueHelper.findValue("custom_login_page_enabled", data),
     
    3833                admin_notification: $valueHelper.findValue("admin_notification", data),
    3934                admin_email: $valueHelper.findValue("admin_email", data).split(";"),
    40                 from_email: $valueHelper.findValue("from_email", data).split(";"),
     35                from_email: $valueHelper.findValue("from_email", data),
    4136                allow_xmlrpc_login: $valueHelper.findValue("allow_xmlrpc_login", data)
    4237            };
     
    4944
    5045            $scope.permission = {
    51                 sso: $valueHelper.findPermission("sso", data),
    52                 sso_user: $valueHelper.findPermission("sso_user", data),
    53                 sso_password: $valueHelper.findPermission("sso_password", data),
    54                 sso_environment_variable: $valueHelper.findPermission("sso_environment_variable", data),
    55                 sso_disable_for_xmlrpc: $valueHelper.findPermission("sso_disable_for_xmlrpc", data),
    5646                enable_smartcard_user_login: $valueHelper.findPermission("enable_smartcard_user_login", data),
    5747                custom_login_page_enabled: $valueHelper.findPermission("custom_login_page_enabled", data),
     
    6858        $scope.$on('validation', function (event, data) {
    6959            $scope.messages = {
    70                 sso: $valueHelper.findMessage("sso", data),
    71                 sso_user: $valueHelper.findMessage("sso_user", data),
    72                 sso_password: $valueHelper.findMessage("sso_password", data),
    73                 sso_environment_variable: $valueHelper.findMessage("sso_environment_variable", data),
    7460                enable_smartcard_user_login: $valueHelper.findMessage("enable_smartcard_user_login", data),
    7561                custom_login_page_enabled: $valueHelper.findMessage("custom_login_page_enabled", data),
  • next-active-directory-integration/trunk/readme.txt

    r2331601 r2513920  
    22Contributors: neosit,tobi823,fatsquirrel,schakko,medan123
    33Tags: authentication, active directory, ldap, authorization, security, windows, sso
    4 Requires at least: 5.0
    5 Tested up to: 5.4
    6 Stable tag: 2.1.12
     4Requires at least: 5.4
     5Tested up to: 5.7
     6Stable tag: 2.2.0
    77License: GPLv3
    88
     
    3636* Set users local WordPress password on first and/or on every successful login
    3737* Option to disable fallback to local (WordPress) authentication.
     38* Support for Active Directory forest environments.
    3839* and much much more
    3940
     
    4849* Login with WooCommerce: Let WooCommerce users log in by using NADI
    4950* WP-CLI: Execute common NADI tasks (Sync to WordPress, Sync to AD) with help of WP-CLI
     51* Active Directory Forest: Be able to use one WordPress instance with your whole Active Directory forest environment
    5052
    5153= Requirements =
    5254
    53 * WordPress since 5.0
     55* WordPress since 5.4
    5456* PHP >= 7.2
    5557* LDAP support
     
    8082
    8183= Requirements =
    82 To install Next Active Directory Integration you need at least WordPress 5.0 and PHP 7.2
     84To install Next Active Directory Integration you need at least WordPress 5.4 and PHP 7.2
    8385
    8486Although only tested with Apache 2.2 and 2.4 *NADI* should work with all other common web servers like nginx and IIS.
     
    127129
    128130For detailed information you can visit the official [GitHub repository of Next Active Directory Integration](https://github.com/NeosIT/active-directory-integration2)
     131
     132
     133= 2.2.0 =
     134* ADDED: Kerberos principals are no longer treated as userPrincipalNames (ADI-715)
     135* ADDED: When using Kerberos SSO principals, you can map the Kerberos realm to multiple UPN suffixes (requires *Active Directory Forest* premium extension) (ADI-715)
     136* ADDED: When using NADI in an AD forest, you can now specify all SIDs of the connected domains (requires *Active Directory Forest* premium extension) (ADI-715)
     137* FIXED: When using a Global Catalog (GC), users with same sAMAccountName but different userPrincipalNames are not assigned correct during authentication (NADIS-133)
     138* FIXED-SECURITY: Users with same UPN prefix and password but different UPN suffix would be logged in with the wrong account (ADI-716)
     139* CHANGED: WordPress 5.6.1 compatibility has been checked
     140* CHANGED: WordPress 5.7 compatibility has been checked
     141* CHANGED: PHP 8.0 compatibility has been added (ADI-718, gh-#132, gh-#137)
     142* FIXED: Deprecation warning when trying to send mail notification for blocked users (ADI-719)
     143* FIXED: Option "Blog admin sets the option value." had no effect in Multisite environments (gh-#124)
     144* DEPRECATION-WARNING: For the upcoming release 2.3.0 we will remove "Internal password migration" (gh-#136), "Automatic user creation" (gh-#134) and "Email address conflict handling" (gh-#133)
     145* DEV: Slightly transition new issues to GitHub instead of internal Jira
    129146
    130147= 2.1.12 =
  • next-active-directory-integration/trunk/vendor/adLDAP/adLDAP.php

    r2331595 r2513920  
    13311331
    13321332        if ($isGUID === true) {
    1333             $username = $this->strguid2hex($username);
     1333            $username = self::strguid2hex($username);
    13341334            $filter="objectguid=".$username;
    13351335        }
     
    13691369
    13701370    /**
    1371      * Get a configuration etnry form the CN=Partitions,CN=Configuration object
     1371     * Get a configuration entry form the CN=Partitions,CN=Configuration object
    13721372     *
    13731373     * @param $filter
     
    25852585
    25862586        $gsid = substr_replace($usersid,pack('V',$gid),strlen($usersid)-4,4);
    2587         $filter='(objectsid='.$this->getTextSID($gsid).')';
     2587        $filter='(objectsid='. self::convertBinarySidToString($gsid).')';
    25882588        $fields=array("samaccountname","distinguishedname");
    25892589        $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
     
    25972597        return false;
    25982598     }
    2599      
    2600     /**
    2601     * Convert a binary SID to a text SID
    2602     *
    2603     * @param string $binsid A Binary SID
    2604     * @return string
    2605     */
    2606      protected function getTextSID($binsid) {
    2607         $hex_sid = bin2hex($binsid);
    2608         $rev = hexdec(substr($hex_sid, 0, 2));
    2609         $subcount = hexdec(substr($hex_sid, 2, 2));
    2610         $auth = hexdec(substr($hex_sid, 4, 12));
    2611         $result = "$rev-$auth";
    2612 
    2613         for ($x=0;$x < $subcount; $x++) {
    2614             $subauth[$x] =
    2615                 hexdec($this->little_endian(substr($hex_sid, 16 + ($x * 8), 8)));
    2616                 $result .= "-" . $subauth[$x];
    2617         }
    2618 
    2619         // Cheat by tacking on the S-
    2620         return 'S-' . $result;
    2621      }
     2599
     2600    /**
     2601     * Convert a binary SID to a text SID
     2602     *
     2603     * @param string $binsid A Binary SID
     2604     * @return string
     2605     */
     2606    public static function convertBinarySidToString($binsid)
     2607    {
     2608        $hex_sid = bin2hex($binsid);
     2609        $rev = hexdec(substr($hex_sid, 0, 2));
     2610        $subcount = hexdec(substr($hex_sid, 2, 2));
     2611        $auth = hexdec(substr($hex_sid, 4, 12));
     2612        $result = "$rev-$auth";
     2613
     2614        for ($x = 0; $x < $subcount; $x++) {
     2615            $subauth[$x] =
     2616                hexdec(self::little_endian(substr($hex_sid, 16 + ($x * 8), 8)));
     2617            $result .= "-" . $subauth[$x];
     2618        }
     2619
     2620        // Cheat by tacking on the S-
     2621        return 'S-' . $result;
     2622    }
     2623
     2624    /**
     2625     * Converts the given string into little endian hex format
     2626     * @param string $int
     2627     * @return string
     2628     */
     2629    public static function toInt32LittleEndianHex($int)
     2630    {
     2631        $endian = unpack("N", pack("L", intval($int)));
     2632        return sprintf("%'08X", $endian[1]);
     2633    }
     2634
     2635    /**
     2636     * Converts a SID string to hex.
     2637     * "S-1-5-21-2127521184-1604012920-1887927527-72713" will be converted to "010500000000000515000000A065CF7E784B9B5FE77C8770091C0100"
     2638     *
     2639     * @see https://devblogs.microsoft.com/oldnewthing/20040315-00/?p=40253
     2640     * @see https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid
     2641     * @see https://en.wikipedia.org/wiki/Security_Identifier
     2642     *
     2643     * @param string $sid "S-1-5-21-2127521184-1604012920-1887927527-72713"
     2644     * @return string "010500000000000515000000A065CF7E784B9B5FE77C8770091C0100"
     2645     */
     2646    public static function sidStringToHex($sid)
     2647    {
     2648        $parts = explode("-", $sid);
     2649
     2650        $revision = sprintf('%02X', $parts[1]);    // 1
     2651        $numberOfDashes = sprintf('%02X', substr_count($sid, '-') - 2); //
     2652        $identifierAuthority = sprintf('%012X', $parts[2]); // 5
     2653        $subAuthorities = ""; // 21-2127521184-1604012920-1887927527-72713
     2654
     2655        for ($i = 3; $i < sizeof($parts); $i++) {
     2656            $subAuthorities .= self::toInt32LittleEndianHex($parts[$i]);
     2657        }
     2658
     2659        return $revision . $numberOfDashes . $identifierAuthority . $subAuthorities;
     2660    }
    26222661     
    26232662    /**
     
    26272666    * @return string
    26282667    */
    2629      protected function little_endian($hex) {
     2668     public static function little_endian($hex) {
    26302669        $result = '';
    26312670        for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
     
    26352674     }
    26362675
    2637     /**
    2638      * Convert binary Object SID to string
    2639      *
    2640      * @author [email protected]
    2641      * @param $bin
    2642      * @return $string
    2643      */
    2644     public function convertObjectSidBinaryToString($bin) {
    2645        return $this->getTextSID($bin);
    2646     }
    2647      
    26482676    /**
    26492677    * Converts a binary attribute to a string
     
    26902718    * @return string
    26912719    */
    2692     protected function strguid2hex($strGUID) {
     2720    public static function strguid2hex($strGUID) {
    26932721        $strGUID = str_replace('-', '', $strGUID);
    26942722
  • next-active-directory-integration/trunk/vendor/autoload.php

    r2331603 r2513920  
    55require_once __DIR__ . '/composer/autoload_real.php';
    66
    7 return ComposerAutoloaderInit1f93e1293d0d14fe15942807ee39d508::getLoader();
     7return ComposerAutoloaderInitde0ddec4866a627b4af09bbe789ba7cd::getLoader();
  • next-active-directory-integration/trunk/vendor/composer/ClassLoader.php

    r2069979 r2513920  
    3838 * @author Fabien Potencier <[email protected]>
    3939 * @author Jordi Boggiano <[email protected]>
    40  * @see    http://www.php-fig.org/psr/psr-0/
    41  * @see    http://www.php-fig.org/psr/psr-4/
     40 * @see    https://www.php-fig.org/psr/psr-0/
     41 * @see    https://www.php-fig.org/psr/psr-4/
    4242 */
    4343class ClassLoader
    4444{
     45    private $vendorDir;
     46
    4547    // PSR-4
    4648    private $prefixLengthsPsr4 = array();
     
    5860    private $apcuPrefix;
    5961
     62    private static $registeredLoaders = array();
     63
     64    public function __construct($vendorDir = null)
     65    {
     66        $this->vendorDir = $vendorDir;
     67    }
     68
    6069    public function getPrefixes()
    6170    {
    6271        if (!empty($this->prefixesPsr0)) {
    63             return call_user_func_array('array_merge', $this->prefixesPsr0);
     72            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
    6473        }
    6574
     
    301310    {
    302311        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
     312
     313        if (null === $this->vendorDir) {
     314            return;
     315        }
     316
     317        if ($prepend) {
     318            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
     319        } else {
     320            unset(self::$registeredLoaders[$this->vendorDir]);
     321            self::$registeredLoaders[$this->vendorDir] = $this;
     322        }
    303323    }
    304324
     
    309329    {
    310330        spl_autoload_unregister(array($this, 'loadClass'));
     331
     332        if (null !== $this->vendorDir) {
     333            unset(self::$registeredLoaders[$this->vendorDir]);
     334        }
    311335    }
    312336
     
    366390
    367391        return $file;
     392    }
     393
     394    /**
     395     * Returns the currently registered loaders indexed by their corresponding vendor directories.
     396     *
     397     * @return self[]
     398     */
     399    public static function getRegisteredLoaders()
     400    {
     401        return self::$registeredLoaders;
    368402    }
    369403
  • next-active-directory-integration/trunk/vendor/composer/autoload_classmap.php

    r1756617 r2513920  
    77
    88return array(
     9    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    910    'Defuse\\Crypto\\Core' => $vendorDir . '/defuse/php-encryption/src/Core.php',
    1011    'Defuse\\Crypto\\Crypto' => $vendorDir . '/defuse/php-encryption/src/Crypto.php',
  • next-active-directory-integration/trunk/vendor/composer/autoload_real.php

    r2331603 r2513920  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit1f93e1293d0d14fe15942807ee39d508
     5class ComposerAutoloaderInitde0ddec4866a627b4af09bbe789ba7cd
    66{
    77    private static $loader;
     
    1414    }
    1515
     16    /**
     17     * @return \Composer\Autoload\ClassLoader
     18     */
    1619    public static function getLoader()
    1720    {
     
    2023        }
    2124
    22         spl_autoload_register(array('ComposerAutoloaderInit1f93e1293d0d14fe15942807ee39d508', 'loadClassLoader'), true, true);
    23         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    24         spl_autoload_unregister(array('ComposerAutoloaderInit1f93e1293d0d14fe15942807ee39d508', 'loadClassLoader'));
     25        require __DIR__ . '/platform_check.php';
     26
     27        spl_autoload_register(array('ComposerAutoloaderInitde0ddec4866a627b4af09bbe789ba7cd', 'loadClassLoader'), true, true);
     28        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
     29        spl_autoload_unregister(array('ComposerAutoloaderInitde0ddec4866a627b4af09bbe789ba7cd', 'loadClassLoader'));
    2530
    2631        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
    2732        if ($useStaticLoader) {
    28             require_once __DIR__ . '/autoload_static.php';
     33            require __DIR__ . '/autoload_static.php';
    2934
    30             call_user_func(\Composer\Autoload\ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::getInitializer($loader));
     35            call_user_func(\Composer\Autoload\ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::getInitializer($loader));
    3136        } else {
    3237            $map = require __DIR__ . '/autoload_namespaces.php';
     
    4954
    5055        if ($useStaticLoader) {
    51             $includeFiles = Composer\Autoload\ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::$files;
     56            $includeFiles = Composer\Autoload\ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::$files;
    5257        } else {
    5358            $includeFiles = require __DIR__ . '/autoload_files.php';
    5459        }
    5560        foreach ($includeFiles as $fileIdentifier => $file) {
    56             composerRequire1f93e1293d0d14fe15942807ee39d508($fileIdentifier, $file);
     61            composerRequirede0ddec4866a627b4af09bbe789ba7cd($fileIdentifier, $file);
    5762        }
    5863
     
    6166}
    6267
    63 function composerRequire1f93e1293d0d14fe15942807ee39d508($fileIdentifier, $file)
     68function composerRequirede0ddec4866a627b4af09bbe789ba7cd($fileIdentifier, $file)
    6469{
    6570    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • next-active-directory-integration/trunk/vendor/composer/autoload_static.php

    r2331603 r2513920  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit1f93e1293d0d14fe15942807ee39d508
     7class ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd
    88{
    99    public static $files = array (
     
    6161
    6262    public static $classMap = array (
     63        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
    6364        'Defuse\\Crypto\\Core' => __DIR__ . '/..' . '/defuse/php-encryption/src/Core.php',
    6465        'Defuse\\Crypto\\Crypto' => __DIR__ . '/..' . '/defuse/php-encryption/src/Crypto.php',
     
    8081    {
    8182        return \Closure::bind(function () use ($loader) {
    82             $loader->prefixLengthsPsr4 = ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::$prefixLengthsPsr4;
    83             $loader->prefixDirsPsr4 = ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::$prefixDirsPsr4;
    84             $loader->prefixesPsr0 = ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::$prefixesPsr0;
    85             $loader->classMap = ComposerStaticInit1f93e1293d0d14fe15942807ee39d508::$classMap;
     83            $loader->prefixLengthsPsr4 = ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::$prefixLengthsPsr4;
     84            $loader->prefixDirsPsr4 = ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::$prefixDirsPsr4;
     85            $loader->prefixesPsr0 = ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::$prefixesPsr0;
     86            $loader->classMap = ComposerStaticInitde0ddec4866a627b4af09bbe789ba7cd::$classMap;
    8687
    8788        }, null, ClassLoader::class);
  • next-active-directory-integration/trunk/vendor/composer/installed.json

    r2331595 r2513920  
    1 [
    2     {
    3         "name": "defuse/php-encryption",
    4         "version": "2.0.3",
    5         "version_normalized": "2.0.3.0",
    6         "source": {
    7             "type": "git",
    8             "url": "https://github.com/defuse/php-encryption.git",
    9             "reference": "2c6fea3d9a4eaaa8cef86b2a89f3660818117b33"
     1{
     2    "packages": [
     3        {
     4            "name": "defuse/php-encryption",
     5            "version": "2.0.3",
     6            "version_normalized": "2.0.3.0",
     7            "source": {
     8                "type": "git",
     9                "url": "https://github.com/defuse/php-encryption.git",
     10                "reference": "2c6fea3d9a4eaaa8cef86b2a89f3660818117b33"
     11            },
     12            "dist": {
     13                "type": "zip",
     14                "url": "https://api.github.com/repos/defuse/php-encryption/zipball/2c6fea3d9a4eaaa8cef86b2a89f3660818117b33",
     15                "reference": "2c6fea3d9a4eaaa8cef86b2a89f3660818117b33",
     16                "shasum": ""
     17            },
     18            "require": {
     19                "ext-openssl": "*",
     20                "paragonie/random_compat": "~2.0",
     21                "php": ">=5.4.0"
     22            },
     23            "require-dev": {
     24                "nikic/php-parser": "^2.0"
     25            },
     26            "time": "2016-10-10T15:20:26+00:00",
     27            "type": "library",
     28            "installation-source": "dist",
     29            "autoload": {
     30                "classmap": [
     31                    "src"
     32                ]
     33            },
     34            "notification-url": "https://packagist.org/downloads/",
     35            "license": [
     36                "MIT"
     37            ],
     38            "authors": [
     39                {
     40                    "name": "Taylor Hornby",
     41                    "email": "[email protected]",
     42                    "homepage": "https://defuse.ca/"
     43                },
     44                {
     45                    "name": "Scott Arciszewski",
     46                    "email": "[email protected]",
     47                    "homepage": "https://paragonie.com"
     48                }
     49            ],
     50            "description": "Secure PHP Encryption Library",
     51            "keywords": [
     52                "aes",
     53                "authenticated encryption",
     54                "cipher",
     55                "crypto",
     56                "cryptography",
     57                "encrypt",
     58                "encryption",
     59                "openssl",
     60                "security",
     61                "symmetric key cryptography"
     62            ],
     63            "support": {
     64                "issues": "https://github.com/defuse/php-encryption/issues",
     65                "source": "https://github.com/defuse/php-encryption/tree/master"
     66            },
     67            "install-path": "../defuse/php-encryption"
    1068        },
    11         "dist": {
    12             "type": "zip",
    13             "url": "https://api.github.com/repos/defuse/php-encryption/zipball/2c6fea3d9a4eaaa8cef86b2a89f3660818117b33",
    14             "reference": "2c6fea3d9a4eaaa8cef86b2a89f3660818117b33",
    15             "shasum": ""
     69        {
     70            "name": "monolog/monolog",
     71            "version": "1.26.0",
     72            "version_normalized": "1.26.0.0",
     73            "source": {
     74                "type": "git",
     75                "url": "https://github.com/Seldaek/monolog.git",
     76                "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33"
     77            },
     78            "dist": {
     79                "type": "zip",
     80                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33",
     81                "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33",
     82                "shasum": ""
     83            },
     84            "require": {
     85                "php": ">=5.3.0",
     86                "psr/log": "~1.0"
     87            },
     88            "provide": {
     89                "psr/log-implementation": "1.0.0"
     90            },
     91            "require-dev": {
     92                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
     93                "doctrine/couchdb": "~1.0@dev",
     94                "graylog2/gelf-php": "~1.0",
     95                "php-amqplib/php-amqplib": "~2.4",
     96                "php-console/php-console": "^3.1.3",
     97                "phpstan/phpstan": "^0.12.59",
     98                "phpunit/phpunit": "~4.5",
     99                "ruflin/elastica": ">=0.90 <3.0",
     100                "sentry/sentry": "^0.13",
     101                "swiftmailer/swiftmailer": "^5.3|^6.0"
     102            },
     103            "suggest": {
     104                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
     105                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
     106                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
     107                "ext-mongo": "Allow sending log messages to a MongoDB server",
     108                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
     109                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
     110                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
     111                "php-console/php-console": "Allow sending log messages to Google Chrome",
     112                "rollbar/rollbar": "Allow sending log messages to Rollbar",
     113                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
     114                "sentry/sentry": "Allow sending log messages to a Sentry server"
     115            },
     116            "time": "2020-12-14T12:56:38+00:00",
     117            "type": "library",
     118            "installation-source": "dist",
     119            "autoload": {
     120                "psr-4": {
     121                    "Monolog\\": "src/Monolog"
     122                }
     123            },
     124            "notification-url": "https://packagist.org/downloads/",
     125            "license": [
     126                "MIT"
     127            ],
     128            "authors": [
     129                {
     130                    "name": "Jordi Boggiano",
     131                    "email": "[email protected]",
     132                    "homepage": "http://seld.be"
     133                }
     134            ],
     135            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
     136            "homepage": "http://github.com/Seldaek/monolog",
     137            "keywords": [
     138                "log",
     139                "logging",
     140                "psr-3"
     141            ],
     142            "support": {
     143                "issues": "https://github.com/Seldaek/monolog/issues",
     144                "source": "https://github.com/Seldaek/monolog/tree/1.26.0"
     145            },
     146            "funding": [
     147                {
     148                    "url": "https://github.com/Seldaek",
     149                    "type": "github"
     150                },
     151                {
     152                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
     153                    "type": "tidelift"
     154                }
     155            ],
     156            "install-path": "../monolog/monolog"
    16157        },
    17         "require": {
    18             "ext-openssl": "*",
    19             "paragonie/random_compat": "~2.0",
    20             "php": ">=5.4.0"
     158        {
     159            "name": "paragonie/random_compat",
     160            "version": "v2.0.19",
     161            "version_normalized": "2.0.19.0",
     162            "source": {
     163                "type": "git",
     164                "url": "https://github.com/paragonie/random_compat.git",
     165                "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241"
     166            },
     167            "dist": {
     168                "type": "zip",
     169                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241",
     170                "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241",
     171                "shasum": ""
     172            },
     173            "require": {
     174                "php": ">=5.2.0"
     175            },
     176            "require-dev": {
     177                "phpunit/phpunit": "4.*|5.*"
     178            },
     179            "suggest": {
     180                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
     181            },
     182            "time": "2020-10-15T10:06:57+00:00",
     183            "type": "library",
     184            "installation-source": "dist",
     185            "autoload": {
     186                "files": [
     187                    "lib/random.php"
     188                ]
     189            },
     190            "notification-url": "https://packagist.org/downloads/",
     191            "license": [
     192                "MIT"
     193            ],
     194            "authors": [
     195                {
     196                    "name": "Paragon Initiative Enterprises",
     197                    "email": "[email protected]",
     198                    "homepage": "https://paragonie.com"
     199                }
     200            ],
     201            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
     202            "keywords": [
     203                "csprng",
     204                "polyfill",
     205                "pseudorandom",
     206                "random"
     207            ],
     208            "support": {
     209                "email": "[email protected]",
     210                "issues": "https://github.com/paragonie/random_compat/issues",
     211                "source": "https://github.com/paragonie/random_compat"
     212            },
     213            "install-path": "../paragonie/random_compat"
    21214        },
    22         "require-dev": {
    23             "nikic/php-parser": "^2.0"
     215        {
     216            "name": "psr/log",
     217            "version": "1.1.3",
     218            "version_normalized": "1.1.3.0",
     219            "source": {
     220                "type": "git",
     221                "url": "https://github.com/php-fig/log.git",
     222                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
     223            },
     224            "dist": {
     225                "type": "zip",
     226                "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
     227                "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
     228                "shasum": ""
     229            },
     230            "require": {
     231                "php": ">=5.3.0"
     232            },
     233            "time": "2020-03-23T09:12:05+00:00",
     234            "type": "library",
     235            "extra": {
     236                "branch-alias": {
     237                    "dev-master": "1.1.x-dev"
     238                }
     239            },
     240            "installation-source": "dist",
     241            "autoload": {
     242                "psr-4": {
     243                    "Psr\\Log\\": "Psr/Log/"
     244                }
     245            },
     246            "notification-url": "https://packagist.org/downloads/",
     247            "license": [
     248                "MIT"
     249            ],
     250            "authors": [
     251                {
     252                    "name": "PHP-FIG",
     253                    "homepage": "http://www.php-fig.org/"
     254                }
     255            ],
     256            "description": "Common interface for logging libraries",
     257            "homepage": "https://github.com/php-fig/log",
     258            "keywords": [
     259                "log",
     260                "psr",
     261                "psr-3"
     262            ],
     263            "support": {
     264                "source": "https://github.com/php-fig/log/tree/1.1.3"
     265            },
     266            "install-path": "../psr/log"
    24267        },
    25         "time": "2016-10-10T15:20:26+00:00",
    26         "type": "library",
    27         "installation-source": "dist",
    28         "autoload": {
    29             "classmap": [
    30                 "src"
    31             ]
     268        {
     269            "name": "symfony/polyfill-ctype",
     270            "version": "v1.22.1",
     271            "version_normalized": "1.22.1.0",
     272            "source": {
     273                "type": "git",
     274                "url": "https://github.com/symfony/polyfill-ctype.git",
     275                "reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
     276            },
     277            "dist": {
     278                "type": "zip",
     279                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
     280                "reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
     281                "shasum": ""
     282            },
     283            "require": {
     284                "php": ">=7.1"
     285            },
     286            "suggest": {
     287                "ext-ctype": "For best performance"
     288            },
     289            "time": "2021-01-07T16:49:33+00:00",
     290            "type": "library",
     291            "extra": {
     292                "branch-alias": {
     293                    "dev-main": "1.22-dev"
     294                },
     295                "thanks": {
     296                    "name": "symfony/polyfill",
     297                    "url": "https://github.com/symfony/polyfill"
     298                }
     299            },
     300            "installation-source": "dist",
     301            "autoload": {
     302                "psr-4": {
     303                    "Symfony\\Polyfill\\Ctype\\": ""
     304                },
     305                "files": [
     306                    "bootstrap.php"
     307                ]
     308            },
     309            "notification-url": "https://packagist.org/downloads/",
     310            "license": [
     311                "MIT"
     312            ],
     313            "authors": [
     314                {
     315                    "name": "Gert de Pagter",
     316                    "email": "[email protected]"
     317                },
     318                {
     319                    "name": "Symfony Community",
     320                    "homepage": "https://symfony.com/contributors"
     321                }
     322            ],
     323            "description": "Symfony polyfill for ctype functions",
     324            "homepage": "https://symfony.com",
     325            "keywords": [
     326                "compatibility",
     327                "ctype",
     328                "polyfill",
     329                "portable"
     330            ],
     331            "support": {
     332                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
     333            },
     334            "funding": [
     335                {
     336                    "url": "https://symfony.com/sponsor",
     337                    "type": "custom"
     338                },
     339                {
     340                    "url": "https://github.com/fabpot",
     341                    "type": "github"
     342                },
     343                {
     344                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
     345                    "type": "tidelift"
     346                }
     347            ],
     348            "install-path": "../symfony/polyfill-ctype"
    32349        },
    33         "notification-url": "https://packagist.org/downloads/",
    34         "license": [
    35             "MIT"
    36         ],
    37         "authors": [
    38             {
    39                 "name": "Taylor Hornby",
    40                 "email": "[email protected]",
    41                 "homepage": "https://defuse.ca/"
    42             },
    43             {
    44                 "name": "Scott Arciszewski",
    45                 "email": "[email protected]",
    46                 "homepage": "https://paragonie.com"
    47             }
    48         ],
    49         "description": "Secure PHP Encryption Library",
    50         "keywords": [
    51             "aes",
    52             "authenticated encryption",
    53             "cipher",
    54             "crypto",
    55             "cryptography",
    56             "encrypt",
    57             "encryption",
    58             "openssl",
    59             "security",
    60             "symmetric key cryptography"
    61         ]
    62     },
    63     {
    64         "name": "monolog/monolog",
    65         "version": "1.25.4",
    66         "version_normalized": "1.25.4.0",
    67         "source": {
    68             "type": "git",
    69             "url": "https://github.com/Seldaek/monolog.git",
    70             "reference": "3022efff205e2448b560c833c6fbbf91c3139168"
    71         },
    72         "dist": {
    73             "type": "zip",
    74             "url": "https://api.github.com/repos/Seldaek/monolog/zipball/3022efff205e2448b560c833c6fbbf91c3139168",
    75             "reference": "3022efff205e2448b560c833c6fbbf91c3139168",
    76             "shasum": ""
    77         },
    78         "require": {
    79             "php": ">=5.3.0",
    80             "psr/log": "~1.0"
    81         },
    82         "provide": {
    83             "psr/log-implementation": "1.0.0"
    84         },
    85         "require-dev": {
    86             "aws/aws-sdk-php": "^2.4.9 || ^3.0",
    87             "doctrine/couchdb": "~1.0@dev",
    88             "graylog2/gelf-php": "~1.0",
    89             "php-amqplib/php-amqplib": "~2.4",
    90             "php-console/php-console": "^3.1.3",
    91             "php-parallel-lint/php-parallel-lint": "^1.0",
    92             "phpunit/phpunit": "~4.5",
    93             "ruflin/elastica": ">=0.90 <3.0",
    94             "sentry/sentry": "^0.13",
    95             "swiftmailer/swiftmailer": "^5.3|^6.0"
    96         },
    97         "suggest": {
    98             "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
    99             "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
    100             "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
    101             "ext-mongo": "Allow sending log messages to a MongoDB server",
    102             "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
    103             "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
    104             "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
    105             "php-console/php-console": "Allow sending log messages to Google Chrome",
    106             "rollbar/rollbar": "Allow sending log messages to Rollbar",
    107             "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
    108             "sentry/sentry": "Allow sending log messages to a Sentry server"
    109         },
    110         "time": "2020-05-22T07:31:27+00:00",
    111         "type": "library",
    112         "extra": {
    113             "branch-alias": {
    114                 "dev-master": "2.0.x-dev"
    115             }
    116         },
    117         "installation-source": "dist",
    118         "autoload": {
    119             "psr-4": {
    120                 "Monolog\\": "src/Monolog"
    121             }
    122         },
    123         "notification-url": "https://packagist.org/downloads/",
    124         "license": [
    125             "MIT"
    126         ],
    127         "authors": [
    128             {
    129                 "name": "Jordi Boggiano",
    130                 "email": "[email protected]",
    131                 "homepage": "http://seld.be"
    132             }
    133         ],
    134         "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
    135         "homepage": "http://github.com/Seldaek/monolog",
    136         "keywords": [
    137             "log",
    138             "logging",
    139             "psr-3"
    140         ]
    141     },
    142     {
    143         "name": "paragonie/random_compat",
    144         "version": "v2.0.18",
    145         "version_normalized": "2.0.18.0",
    146         "source": {
    147             "type": "git",
    148             "url": "https://github.com/paragonie/random_compat.git",
    149             "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db"
    150         },
    151         "dist": {
    152             "type": "zip",
    153             "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db",
    154             "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db",
    155             "shasum": ""
    156         },
    157         "require": {
    158             "php": ">=5.2.0"
    159         },
    160         "require-dev": {
    161             "phpunit/phpunit": "4.*|5.*"
    162         },
    163         "suggest": {
    164             "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
    165         },
    166         "time": "2019-01-03T20:59:08+00:00",
    167         "type": "library",
    168         "installation-source": "dist",
    169         "autoload": {
    170             "files": [
    171                 "lib/random.php"
    172             ]
    173         },
    174         "notification-url": "https://packagist.org/downloads/",
    175         "license": [
    176             "MIT"
    177         ],
    178         "authors": [
    179             {
    180                 "name": "Paragon Initiative Enterprises",
    181                 "email": "[email protected]",
    182                 "homepage": "https://paragonie.com"
    183             }
    184         ],
    185         "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
    186         "keywords": [
    187             "csprng",
    188             "polyfill",
    189             "pseudorandom",
    190             "random"
    191         ]
    192     },
    193     {
    194         "name": "psr/log",
    195         "version": "1.1.3",
    196         "version_normalized": "1.1.3.0",
    197         "source": {
    198             "type": "git",
    199             "url": "https://github.com/php-fig/log.git",
    200             "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
    201         },
    202         "dist": {
    203             "type": "zip",
    204             "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
    205             "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
    206             "shasum": ""
    207         },
    208         "require": {
    209             "php": ">=5.3.0"
    210         },
    211         "time": "2020-03-23T09:12:05+00:00",
    212         "type": "library",
    213         "extra": {
    214             "branch-alias": {
    215                 "dev-master": "1.1.x-dev"
    216             }
    217         },
    218         "installation-source": "dist",
    219         "autoload": {
    220             "psr-4": {
    221                 "Psr\\Log\\": "Psr/Log/"
    222             }
    223         },
    224         "notification-url": "https://packagist.org/downloads/",
    225         "license": [
    226             "MIT"
    227         ],
    228         "authors": [
    229             {
    230                 "name": "PHP-FIG",
    231                 "homepage": "http://www.php-fig.org/"
    232             }
    233         ],
    234         "description": "Common interface for logging libraries",
    235         "homepage": "https://github.com/php-fig/log",
    236         "keywords": [
    237             "log",
    238             "psr",
    239             "psr-3"
    240         ]
    241     },
    242     {
    243         "name": "symfony/polyfill-ctype",
    244         "version": "v1.17.1",
    245         "version_normalized": "1.17.1.0",
    246         "source": {
    247             "type": "git",
    248             "url": "https://github.com/symfony/polyfill-ctype.git",
    249             "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
    250         },
    251         "dist": {
    252             "type": "zip",
    253             "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
    254             "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
    255             "shasum": ""
    256         },
    257         "require": {
    258             "php": ">=5.3.3"
    259         },
    260         "suggest": {
    261             "ext-ctype": "For best performance"
    262         },
    263         "time": "2020-06-06T08:46:27+00:00",
    264         "type": "library",
    265         "extra": {
    266             "branch-alias": {
    267                 "dev-master": "1.17-dev"
    268             },
    269             "thanks": {
    270                 "name": "symfony/polyfill",
    271                 "url": "https://github.com/symfony/polyfill"
    272             }
    273         },
    274         "installation-source": "dist",
    275         "autoload": {
    276             "psr-4": {
    277                 "Symfony\\Polyfill\\Ctype\\": ""
    278             },
    279             "files": [
    280                 "bootstrap.php"
    281             ]
    282         },
    283         "notification-url": "https://packagist.org/downloads/",
    284         "license": [
    285             "MIT"
    286         ],
    287         "authors": [
    288             {
    289                 "name": "Gert de Pagter",
    290                 "email": "[email protected]"
    291             },
    292             {
    293                 "name": "Symfony Community",
    294                 "homepage": "https://symfony.com/contributors"
    295             }
    296         ],
    297         "description": "Symfony polyfill for ctype functions",
    298         "homepage": "https://symfony.com",
    299         "keywords": [
    300             "compatibility",
    301             "ctype",
    302             "polyfill",
    303             "portable"
    304         ]
    305     },
    306     {
    307         "name": "twig/twig",
    308         "version": "v1.41.0",
    309         "version_normalized": "1.41.0.0",
    310         "source": {
    311             "type": "git",
    312             "url": "https://github.com/twigphp/Twig.git",
    313             "reference": "575cd5028362da591facde1ef5d7b94553c375c9"
    314         },
    315         "dist": {
    316             "type": "zip",
    317             "url": "https://api.github.com/repos/twigphp/Twig/zipball/575cd5028362da591facde1ef5d7b94553c375c9",
    318             "reference": "575cd5028362da591facde1ef5d7b94553c375c9",
    319             "shasum": ""
    320         },
    321         "require": {
    322             "php": ">=5.4.0",
    323             "symfony/polyfill-ctype": "^1.8"
    324         },
    325         "require-dev": {
    326             "psr/container": "^1.0",
    327             "symfony/debug": "^2.7",
    328             "symfony/phpunit-bridge": "^3.4.19|^4.1.8"
    329         },
    330         "time": "2019-05-14T11:59:08+00:00",
    331         "type": "library",
    332         "extra": {
    333             "branch-alias": {
    334                 "dev-master": "1.41-dev"
    335             }
    336         },
    337         "installation-source": "dist",
    338         "autoload": {
    339             "psr-0": {
    340                 "Twig_": "lib/"
    341             },
    342             "psr-4": {
    343                 "Twig\\": "src/"
    344             }
    345         },
    346         "notification-url": "https://packagist.org/downloads/",
    347         "license": [
    348             "BSD-3-Clause"
    349         ],
    350         "authors": [
    351             {
    352                 "name": "Fabien Potencier",
    353                 "email": "[email protected]",
    354                 "homepage": "http://fabien.potencier.org",
    355                 "role": "Lead Developer"
    356             },
    357             {
    358                 "name": "Armin Ronacher",
    359                 "email": "[email protected]",
    360                 "role": "Project Founder"
    361             },
    362             {
    363                 "name": "Twig Team",
    364                 "homepage": "https://twig.symfony.com/contributors",
    365                 "role": "Contributors"
    366             }
    367         ],
    368         "description": "Twig, the flexible, fast, and secure template language for PHP",
    369         "homepage": "https://twig.symfony.com",
    370         "keywords": [
    371             "templating"
    372         ]
    373     }
    374 ]
     350        {
     351            "name": "twig/twig",
     352            "version": "v1.41.0",
     353            "version_normalized": "1.41.0.0",
     354            "source": {
     355                "type": "git",
     356                "url": "https://github.com/twigphp/Twig.git",
     357                "reference": "575cd5028362da591facde1ef5d7b94553c375c9"
     358            },
     359            "dist": {
     360                "type": "zip",
     361                "url": "https://api.github.com/repos/twigphp/Twig/zipball/575cd5028362da591facde1ef5d7b94553c375c9",
     362                "reference": "575cd5028362da591facde1ef5d7b94553c375c9",
     363                "shasum": ""
     364            },
     365            "require": {
     366                "php": ">=5.4.0",
     367                "symfony/polyfill-ctype": "^1.8"
     368            },
     369            "require-dev": {
     370                "psr/container": "^1.0",
     371                "symfony/debug": "^2.7",
     372                "symfony/phpunit-bridge": "^3.4.19|^4.1.8"
     373            },
     374            "time": "2019-05-14T11:59:08+00:00",
     375            "type": "library",
     376            "extra": {
     377                "branch-alias": {
     378                    "dev-master": "1.41-dev"
     379                }
     380            },
     381            "installation-source": "dist",
     382            "autoload": {
     383                "psr-0": {
     384                    "Twig_": "lib/"
     385                },
     386                "psr-4": {
     387                    "Twig\\": "src/"
     388                }
     389            },
     390            "notification-url": "https://packagist.org/downloads/",
     391            "license": [
     392                "BSD-3-Clause"
     393            ],
     394            "authors": [
     395                {
     396                    "name": "Fabien Potencier",
     397                    "email": "[email protected]",
     398                    "homepage": "http://fabien.potencier.org",
     399                    "role": "Lead Developer"
     400                },
     401                {
     402                    "name": "Armin Ronacher",
     403                    "email": "[email protected]",
     404                    "role": "Project Founder"
     405                },
     406                {
     407                    "name": "Twig Team",
     408                    "homepage": "https://twig.symfony.com/contributors",
     409                    "role": "Contributors"
     410                }
     411            ],
     412            "description": "Twig, the flexible, fast, and secure template language for PHP",
     413            "homepage": "https://twig.symfony.com",
     414            "keywords": [
     415                "templating"
     416            ],
     417            "support": {
     418                "issues": "https://github.com/twigphp/Twig/issues",
     419                "source": "https://github.com/twigphp/Twig/tree/1.x"
     420            },
     421            "install-path": "../twig/twig"
     422        }
     423    ],
     424    "dev": false,
     425    "dev-package-names": []
     426}
  • next-active-directory-integration/trunk/vendor/monolog/monolog/CHANGELOG.md

    r2331595 r2513920  
     1### 1.26.0 (2020-12-14)
     2
     3  * Added $dateFormat and $removeUsedContextFields arguments to PsrLogMessageProcessor (backport from 2.x)
     4
     5### 1.25.5 (2020-07-23)
     6
     7  * Fixed array access on null in RavenHandler
     8  * Fixed unique_id in WebProcessor not being disableable
     9
    110### 1.25.4 (2020-05-22)
    211
  • next-active-directory-integration/trunk/vendor/monolog/monolog/composer.json

    r2331595 r2513920  
    2727        "swiftmailer/swiftmailer": "^5.3|^6.0",
    2828        "php-console/php-console": "^3.1.3",
    29         "php-parallel-lint/php-parallel-lint": "^1.0"
     29        "phpstan/phpstan": "^0.12.59"
    3030    },
    3131    "suggest": {
     
    5151        "psr/log-implementation": "1.0.0"
    5252    },
    53     "extra": {
    54         "branch-alias": {
    55             "dev-master": "2.0.x-dev"
    56         }
    57     },
    5853    "scripts": {
    59         "test": [
    60             "parallel-lint . --exclude vendor --exclude src/Monolog/Handler/FormattableHandlerInterface.php  --exclude src/Monolog/Handler/FormattableHandlerTrait.php --exclude src/Monolog/Handler/ProcessableHandlerInterface.php --exclude src/Monolog/Handler/ProcessableHandlerTrait.php",
    61             "phpunit"
    62         ]
     54        "test": "vendor/bin/phpunit",
     55        "phpstan": "vendor/bin/phpstan analyse"
    6356    },
    6457    "lock": false
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/ErrorHandler.php

    r2331595 r2513920  
    6363        class_exists('\\Psr\\Log\\LogLevel', true);
    6464
     65        /** @phpstan-ignore-next-line */
    6566        $handler = new static($logger);
    6667        if ($errorLevelMap !== false) {
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php

    r1756617 r2513920  
    7878            $formatted = $this->marshaler->marshalItem($filtered);
    7979        } else {
     80            /** @phpstan-ignore-next-line */
    8081            $formatted = $this->client->formatAttributes($filtered);
    8182        }
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php

    r1986677 r2513920  
    7373     * @see createHeader()
    7474     * @param  array  $record
    75      * @return string
     75     * @return array
    7676     */
    7777    protected function createRecordHeader(array $record)
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php

    r1986677 r2513920  
    2828{
    2929    /**
    30      * @var Publisher the publisher object that sends the message to the server
     30     * @var Publisher|PublisherInterface|IMessagePublisher the publisher object that sends the message to the server
    3131     */
    3232    protected $publisher;
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php

    r2224724 r2513920  
    271271     * from the first record.
    272272     *
    273      * @param $records
     273     * @param array $records
    274274     * @return array
    275275     */
    276     private function combineRecords($records)
     276    private function combineRecords(array $records)
    277277    {
    278278        $batchRecord = null;
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php

    r2224724 r2513920  
    5151
    5252    /**
    53      * @var LineFormatter The formatter to use for the logs generated via handleBatch()
     53     * @var FormatterInterface The formatter to use for the logs generated via handleBatch()
    5454     */
    5555    protected $batchFormatter;
     
    8787        // the record with the highest severity is the "main" one
    8888        $record = array_reduce($records, function ($highest, $record) {
    89             if ($record['level'] > $highest['level']) {
     89            if (null === $highest || $record['level'] > $highest['level']) {
    9090                return $record;
    9191            }
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php

    r2224724 r2513920  
    3737     * @param int                   $level   The minimum logging level at which this handler will be triggered
    3838     * @param bool                  $bubble  Whether the messages that are handled can bubble up the stack or not
    39      * @param int                   $capSize Number of entries to limit list size to
     39     * @param int|false             $capSize Number of entries to limit list size to
    4040     */
    4141    public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false)
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php

    r2331595 r2513920  
    107107            if (!is_resource($this->stream)) {
    108108                $this->stream = null;
    109                 throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
     109
     110                throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url));
    110111            }
    111112        }
     
    154155        }
    155156
    156         return;
     157        return null;
    157158    }
    158159
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Logger.php

    r2224724 r2513920  
    523523     * Converts PSR-3 levels to Monolog ones if necessary
    524524     *
    525      * @param string|int Level number (monolog) or name (PSR-3)
     525     * @param string|int $level Level number (monolog) or name (PSR-3)
    526526     * @return int
    527527     */
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php

    r1986677 r2513920  
    2323class PsrLogMessageProcessor implements ProcessorInterface
    2424{
     25    const SIMPLE_DATE = "Y-m-d\TH:i:s.uP";
     26
     27    /** @var string|null */
     28    private $dateFormat;
     29
     30    /** @var bool */
     31    private $removeUsedContextFields;
     32
     33    /**
     34     * @param string|null $dateFormat              The format of the timestamp: one supported by DateTime::format
     35     * @param bool        $removeUsedContextFields If set to true the fields interpolated into message gets unset
     36     */
     37    public function __construct($dateFormat = null, $removeUsedContextFields = false)
     38    {
     39        $this->dateFormat = $dateFormat;
     40        $this->removeUsedContextFields = $removeUsedContextFields;
     41    }
     42
    2543    /**
    2644     * @param  array $record
     
    3553        $replacements = array();
    3654        foreach ($record['context'] as $key => $val) {
     55            $placeholder = '{' . $key . '}';
     56            if (strpos($record['message'], $placeholder) === false) {
     57                continue;
     58            }
     59
    3760            if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
    38                 $replacements['{'.$key.'}'] = $val;
     61                $replacements[$placeholder] = $val;
     62            } elseif ($val instanceof \DateTime) {
     63                $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
    3964            } elseif (is_object($val)) {
    40                 $replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']';
     65                $replacements[$placeholder] = '[object '.Utils::getClass($val).']';
     66            } elseif (is_array($val)) {
     67                $replacements[$placeholder] = 'array'.Utils::jsonEncode($val, null, true);
    4168            } else {
    42                 $replacements['{'.$key.'}'] = '['.gettype($val).']';
     69                $replacements[$placeholder] = '['.gettype($val).']';
     70            }
     71
     72            if ($this->removeUsedContextFields) {
     73                unset($record['context'][$key]);
    4374            }
    4475        }
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php

    r1986677 r2513920  
    5353        }
    5454
     55        if (isset($this->serverData['UNIQUE_ID'])) {
     56            $this->extraFields['unique_id'] = 'UNIQUE_ID';
     57        }
     58
    5559        if (null !== $extraFields) {
    5660            if (isset($extraFields[0])) {
     
    105109        }
    106110
    107         if (isset($this->serverData['UNIQUE_ID'])) {
    108             $extra['unique_id'] = $this->serverData['UNIQUE_ID'];
    109         }
    110 
    111111        return $extra;
    112112    }
  • next-active-directory-integration/trunk/vendor/monolog/monolog/src/Monolog/Utils.php

    r2331595 r2513920  
    169169     * can be used as a callback for array_walk_recursive.
    170170     *
    171      * @param mixed &$data Input to check and convert if needed
     171     * @param mixed $data Input to check and convert if needed, passed by ref
    172172     * @private
    173173     */
  • next-active-directory-integration/trunk/vendor/symfony/polyfill-ctype/bootstrap.php

    r2331595 r2513920  
    1111
    1212use Symfony\Polyfill\Ctype as p;
     13
     14if (\PHP_VERSION_ID >= 80000) {
     15    return require __DIR__.'/bootstrap80.php';
     16}
    1317
    1418if (!function_exists('ctype_alnum')) {
  • next-active-directory-integration/trunk/vendor/symfony/polyfill-ctype/composer.json

    r2331595 r2513920  
    1717    ],
    1818    "require": {
    19         "php": ">=5.3.3"
     19        "php": ">=7.1"
    2020    },
    2121    "autoload": {
     
    2929    "extra": {
    3030        "branch-alias": {
    31             "dev-master": "1.17-dev"
     31            "dev-main": "1.22-dev"
    3232        },
    3333        "thanks": {
  • next-active-directory-integration/trunk/views/option/element.twig

    r1595001 r2513920  
    4343        {% import "option/element/table.twig" as table %}
    4444        {{ table.create(optionName, permission, inputId, false, false, i18n) }}
    45        
     45
    4646    {% elseif type == constant('NextADInt_Multisite_Option_Type::VERIFICATION_PASSWORD') %}
    4747
     
    5858        {% import "option/element/label.twig" as text %}
    5959        {{ text.create(optionName, permission, inputId) }}
     60
     61    {% elseif type == constant('NextADInt_Multisite_Option_Type::TEXTAREA') %}
     62
     63        {% import "option/element/textarea.twig" as textarea %}
     64        {{ textarea.create(optionName, permission, inputId) }}
    6065
    6166    {% else %}
Note: See TracChangeset for help on using the changeset viewer.