diff --git a/modules/negotiate/docs/negotiate.md b/modules/negotiate/docs/negotiate.md index 3a3dd76f0f81bce8e0313cc0e2288fb737f47026..ad97a2c320b6fccdc2344f475caccb67f14fef75 100644 --- a/modules/negotiate/docs/negotiate.md +++ b/modules/negotiate/docs/negotiate.md @@ -51,7 +51,7 @@ client. All configuration is handled in authsources.php: - 'weblogin' => array( + 'weblogin' => [ 'negotiate:Negotiate', 'keytab' => '/path/to/keytab-file', 'fallback' => 'ldap', @@ -59,19 +59,18 @@ All configuration is handled in authsources.php: 'base' => 'cn=people,dc=example,dc=com', 'adminUser' => 'cn=idp-fallback,cn=services,dc=example,dc=com', 'adminPassword' => 'VerySecretPassphraseHush' - ), - 'ldap' => array( + ], + 'ldap' => [ 'ldap:LDAP', 'hostname' => 'ldap.example.com', 'enable_tls' => TRUE, 'dnpattern' => 'uid=%username%,cn=people,dc=example,dc=com', 'search.enable' => FALSE - ), + ], -`php_krb5` -++++++++++ +### `php_krb5` The processing involving the actual Kerberos ticket handling is done by php_krb5. The package is not yet labeled stable but has worked well @@ -80,7 +79,7 @@ during testing. NOTE! php_krb5 hardcodes the service name in the keytab file to 'HTTP' as of php_krb5-1.0rc2. To change this you need to edit the module code. Be wary of how much space is allocated to the string in -negotiate_auth.c:101. +`negotiate_auth.c:101`. Depending on you apache config you may need a rewrite rule to allow php_krb5 to read the HTTP_AUTHORIZATION header: @@ -94,40 +93,38 @@ Test the Kerberos setup with the following script: <?php if(!extension_loaded('krb5')) { - die('KRB5 Extension not installed'); + die('KRB5 Extension not installed'); } if(!empty($_SERVER['HTTP_AUTHORIZATION'])) { - list($mech, $data) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']); - if(strtolower($mech) == 'basic') { - echo "Client sent basic"; - die('Unsupported request'); - } else if(strtolower($mech) != 'negotiate') { - echo "Couldn't find negotiate"; - die('Unsupported request'); - } - $auth = new KRB5NegotiateAuth('/path/to/keytab'); - $reply = ''; - if($reply = $auth->doAuthentication()) { - header('HTTP/1.1 200 Success'); - echo 'Success - authenticated as ' . $auth->getAuthenticatedUser() . '<br>'; - } else { - echo 'Failed to authN.'; - die(); - } + list($mech, $data) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']); + if(strtolower($mech) == 'basic') { + echo "Client sent basic"; + die('Unsupported request'); + } else if(strtolower($mech) != 'negotiate') { + echo "Couldn't find negotiate"; + die('Unsupported request'); + } + $auth = new KRB5NegotiateAuth('/path/to/keytab'); + $reply = ''; + if($reply = $auth->doAuthentication()) { + header('HTTP/1.1 200 Success'); + echo 'Success - authenticated as ' . $auth->getAuthenticatedUser() . '<br>'; + } else { + echo 'Failed to authN.'; + die(); + } } else { - header('HTTP/1.1 401 Unauthorized'); - header('WWW-Authenticate: Negotiate',false); - echo 'Not authenticated. No HTTP_AUTHORIZATION available.'; - echo 'Check headers sent by the browser and verify that '; - echo 'apache passes them to PHP'; + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Negotiate',false); + echo 'Not authenticated. No HTTP_AUTHORIZATION available.'; + echo 'Check headers sent by the browser and verify that '; + echo 'apache passes them to PHP'; } - ?> -`LDAP` -++++++ +### LDAP LDAP is used to verify the user due to the lack of metadata in Kerberos. A domain can contain lots of kiosk users, non-personal @@ -146,15 +143,14 @@ be a DN to an object with access to search for all relevant user objects and to look up attributes needed by the SP. -`Subnet filtering` -++++++++++++++++++ +### Subnet filtering Subnet is meant to filter which clients you subject to the WWW-Authenticate request. Syntax is: - 'subnet' => array('127.0.0.0/16','192.168.0.0/16'), + 'subnet' => [ '127.0.0.0/16','192.168.0.0/16' ], Browsers, especially IE, behave erratically when they encounter a WWW-Authenticate from the webserver. Included in RFC4559 Negotiate is @@ -167,18 +163,16 @@ currently in the domain should be the only ones that are promted with WWW-Authenticate: Negotiate. -`Enabling/disabling Negotiate from a web browser` -+++++++++++++++++++++++++++++++++++++++++++++++++ +### Enabling/disabling Negotiate from a web browser Included in Negotiate are semi-static web pages for enabling and -disabling Negotiate for any given client. The pages simple set/deletes +disabling Negotiate for any given client. The pages simplly set/delete a cookie that Negotiate will look for when a client attempts AuthN. The help text in the JSON files should be locally overwritten to fully explain which clients are accepted by Negotiate. -`Logout/Login loop and reauthenticating` -++++++++++++++++++++++++++++++++++++++++ +### Logout/Login loop and reauthenticating Due to the automatic AuthN of certain clients and how SPs will automatically redirect clients to the IdP when clients try to access @@ -188,50 +182,51 @@ out user. The consequence of this is that the user will be presented with the login mechanism of the fallback module specified in Negotiate config. -SimpleSamlPhp offers no decent way of adding hooks or piggyback this +SimpleSamlPHP offers no decent way of adding hooks or piggyback this information to the fallback module. In future releases one might add a box of information to the user explaining what's happening. One can add this bit of code to the template in the fallback AuthN module: -// This should be placed in your www script -$nego_session = false; -$nego_perm = false; -$nego_retry = null; -if (array_key_exists('negotiate:authId', $state)) { - $nego = \SimpleSAML\Auth\Source::getById($state['negotiate:authId']); - $mask = $nego->checkMask(); - $disabled = $nego->spDisabledInMetadata($spMetadata); - $session_disabled = $session->getData('negotiate:disable', 'session'); - if ($mask and !$disabled) { - if(array_key_exists('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', $_COOKIE) && - $_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT'] == 'True') { - $nego_perm = true; - } elseif ($session_disabled) { - $retryState = \SimpleSAML\Auth\State::cloneState($state); - unset($retryState[\SimpleSAML\Auth\State::ID]); - $nego_retry = \SimpleSAML\Auth\State::saveState($retryState, '\SimpleSAML\Module\negotiate\Auth\Source\Negotiate.StageId'); - $nego_session = true; + // This should be placed in your www script + $nego_session = false; + $nego_perm = false; + $nego_retry = null; + if (array_key_exists('negotiate:authId', $state)) { + $nego = \SimpleSAML\Auth\Source::getById($state['negotiate:authId']); + $mask = $nego->checkMask(); + $disabled = $nego->spDisabledInMetadata($spMetadata); + $session_disabled = $session->getData('negotiate:disable', 'session'); + if ($mask and !$disabled) { + if(array_key_exists('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', $_COOKIE) && + $_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT'] == 'True') { + $nego_perm = true; + } elseif ($session_disabled) { + $retryState = \SimpleSAML\Auth\State::cloneState($state); + unset($retryState[\SimpleSAML\Auth\State::ID]); + $nego_retry = \SimpleSAML\Auth\State::saveState($retryState, '\SimpleSAML\Module\negotiate\Auth\Source\Negotiate.StageId'); + $nego_session = true; + } } } -} - -// This should reside in your template -if($this->data['nego']['disable_perm']) { - echo '<span id="login-extra-info-uio.no" class="login-extra-info">' - . '<span class="login-extra-info-divider"></span>' - . $this->t('{feide:login:login_uio_negotiate_disabled_permanent_info}') - . '</span>'; -} elseif($this->data['nego']['disable_session']) { - echo '<span id="login-extra-info-uio.no" class="login-extra-info">' - . '<span class="login-extra-info-divider"></span>' - . $this->t('{feide:login:login_uio_negotiate_disabled_session_info}') - . '<br><a href="'.SimpleSAML\Module::getModuleURL('negotiate/retry.php', array('AuthState' => $this->data['nego']['retry_id'])).'">' - . $this->t('{feide:login:login_uio_negotiate_disabled_session_info_link}') - . '</a>' - . '</span>'; -} + + // This should reside in your template + if($this->data['nego']['disable_perm']) { + echo '<span id="login-extra-info-uio.no" class="login-extra-info">' + . '<span class="login-extra-info-divider"></span>' + . $this->t('{feide:login:login_uio_negotiate_disabled_permanent_info}') + . '</span>'; + } elseif($this->data['nego']['disable_session']) { + echo '<span id="login-extra-info-uio.no" class="login-extra-info">' + . '<span class="login-extra-info-divider"></span>' + . $this->t('{feide:login:login_uio_negotiate_disabled_session_info}') + . '<br><a href="'.SimpleSAML\Module::getModuleURL('negotiate/retry.php', [ 'AuthState' => $this->data['nego']['retry_id'] ]).'">' + . $this->t('{feide:login:login_uio_negotiate_disabled_session_info_link}') + . '</a>' + . '</span>'; + } + The above may or may not work right out of the box for you but it is the gist of it. By looking at the state variable, cookie and checking @@ -254,26 +249,25 @@ Negotiate->authenticate() but remaining code in retry.php will be discarded. Other side-effects may occur. -`Clients` -+++++++++ +### Clients -* Internet Explorer +#### Internet Explorer YMMV but generally you need to have your IdP defined in "Internet Options" -> "Security" -> "Local intranet" -> "Sites" -> "Advanced". You also need "Internet Options" -> "Advanced" -> "Security" -> Enable Integrated Windows Authentication" enabled. -* Firefox +#### Firefox Open "about:config". Locate "network.auth.use-sspi" and verify that this is true (on a Windows machine). Next locate "network.negotiate-auth.trusted-uris" and insert your IdP. -* Safari +#### Safari TODO -* Chrome +#### Chrome TODO