From b6511f5c6994c9aae72b6e31a738769978ba7fad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaime=20Pe=CC=81rez?= <jaime.perez@uninett.no>
Date: Mon, 5 Sep 2016 11:57:18 +0200
Subject: [PATCH] Allow setting the 'Comparison' attribute in authentication
 contexts.

Even though the default "exact" is used by most people, and few products support anything else, there's people asking for this.
---
 modules/saml/docs/sp.md             | 23 +++++++++++++++++++++++
 modules/saml/lib/Auth/Source/SP.php | 11 ++++++++++-
 modules/saml/lib/Message.php        |  8 +++++++-
 3 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/modules/saml/docs/sp.md b/modules/saml/docs/sp.md
index 05102fe57..a291cd10a 100644
--- a/modules/saml/docs/sp.md
+++ b/modules/saml/docs/sp.md
@@ -27,6 +27,17 @@ All these parameters override the equivalent option from the configuration.
 
 :   *Note*: SAML 2 specific.
 
+`saml:AuthnContextComparison`
+:   The Comparison attribute of the AuthnContext that will be sent in the login request.
+    This parameter won't be used unless `saml:AuthnContextClassRef` is set and contains one or more values.
+    Possible values:
+    
+    * `SAML2\Constants::COMPARISON_EXACT` (default)
+    * `SAML2\Constants::COMPARISON_BETTER`
+    * `SAML2\Constants::COMPARISON_MINIMUM`
+    * `SAML2\Constants::COMPARISON_MAXIMUM`
+    
+:   *Note*: SAML 2 specific.
 
 `ForceAuthn`
 :   Force authentication allows you to force re-authentication of users even if the user has a SSO session at the IdP.
@@ -125,6 +136,18 @@ Options
 
 :   *Note*: SAML 2 specific.
 
+`AuthnContextComparison`
+:   The Comparison attribute of the AuthnContext that will be sent in the login request.
+    This parameter won't be used unless `saml:AuthnContextClassRef` is set and contains one or more values.
+    Possible values:
+    
+    * `SAML2\Constants::COMPARISON_EXACT` (default)
+    * `SAML2\Constants::COMPARISON_BETTER`
+    * `SAML2\Constants::COMPARISON_MINIMUM`
+    * `SAML2\Constants::COMPARISON_MAXIMUM`
+    
+:   *Note*: SAML 2 specific.
+
 `authproc`
 :   Processing filters that should be run after SP authentication.
     See the [authentication processing filter manual](simplesamlphp-authproc).
diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php
index 0e6cdc5ea..728c97e87 100644
--- a/modules/saml/lib/Auth/Source/SP.php
+++ b/modules/saml/lib/Auth/Source/SP.php
@@ -197,7 +197,16 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source {
 
 		if (isset($state['saml:AuthnContextClassRef'])) {
 			$accr = SimpleSAML\Utils\Arrays::arrayize($state['saml:AuthnContextClassRef']);
-			$ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr));
+			$comp = SAML2\Constants::COMPARISON_EXACT;
+			if (isset($state['saml:AuthnContextComparison']) && in_array($state['AuthnContextComparison'], array(
+						SAML2\Constants::COMPARISON_EXACT,
+						SAML2\Constants::COMPARISON_MINIMUM,
+						SAML2\Constants::COMPARISON_MAXIMUM,
+						SAML2\Constants::COMPARISON_BETTER,
+			))) {
+				$comp = $state['saml:AuthnContextComparison'];
+			}
+			$ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
 		}
 
 		if (isset($state['ForceAuthn'])) {
diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php
index 60fea0e34..7db3df70d 100644
--- a/modules/saml/lib/Message.php
+++ b/modules/saml/lib/Message.php
@@ -447,7 +447,13 @@ class sspmod_saml_Message {
 
 		if ($spMetadata->hasValue('AuthnContextClassRef')) {
 			$accr = $spMetadata->getArrayizeString('AuthnContextClassRef');
-			$ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr));
+			$comp = $spMetadata->getValueValidate('AuthnContextComparison', array(
+				\SAML2\Constants::COMPARISON_EXACT,
+				\SAML2\Constants::COMPARISON_MINIMUM,
+				\SAML2\Constants::COMPARISON_MAXIMUM,
+				\SAML2\Constants::COMPARISON_BETTER,
+			), \SAML2\Constants::COMPARISON_EXACT);
+			$ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
 		}
 
 		self::addRedirectSign($spMetadata, $idpMetadata, $ar);
-- 
GitLab