Fix required field calculation in AuthenticationRequest
authorGergő Tisza <gtisza@wikimedia.org>
Sun, 29 May 2016 21:14:28 +0000 (21:14 +0000)
committerGergő Tisza <gtisza@wikimedia.org>
Mon, 30 May 2016 11:57:58 +0000 (11:57 +0000)
Instead of only flagging fields which are required by a request
needed by all primairy providers, it should be enough if all
requests needed by some primary provider require that field.

Also make CreationReasonAuthenticationRequest non-required so that
the list of required form fields is more in sync with that of
pre-AuthManager code.

Bug: T85853
Change-Id: I9d33bd22295758cc532a260b1848616b41d94f12

includes/auth/AuthenticationRequest.php
includes/auth/CreationReasonAuthenticationRequest.php
tests/phpunit/includes/auth/AuthenticationRequestTest.php

index 3c19b87..f314849 100644 (file)
@@ -281,6 +281,21 @@ abstract class AuthenticationRequest {
        public static function mergeFieldInfo( array $reqs ) {
                $merged = [];
 
+               // fields that are required by some primary providers but not others are not actually required
+               $primaryRequests = array_filter( $reqs, function ( $req ) {
+                       return $req->required === AuthenticationRequest::PRIMARY_REQUIRED;
+               } );
+               $sharedRequiredPrimaryFields = array_reduce( $primaryRequests, function ( $shared, $req ) {
+                       $required = array_keys( array_filter( $req->getFieldInfo(), function ( $options ) {
+                               return empty( $options['optional'] );
+                       } ) );
+                       if ( $shared === null ) {
+                               return $required;
+                       } else {
+                               return array_intersect( $shared, $required );
+                       }
+               }, null );
+
                foreach ( $reqs as $req ) {
                        $info = $req->getFieldInfo();
                        if ( !$info ) {
@@ -288,8 +303,14 @@ abstract class AuthenticationRequest {
                        }
 
                        foreach ( $info as $name => $options ) {
-                               if ( $req->required !== self::REQUIRED ) {
+                               if (
                                        // If the request isn't required, its fields aren't required either.
+                                       $req->required === self::OPTIONAL
+                                       // If there is a primary not requiring this field, no matter how many others do,
+                                       // authentication can proceed without it.
+                                       || $req->required === self::PRIMARY_REQUIRED
+                                               && !in_array( $name, $sharedRequiredPrimaryFields, true )
+                               ) {
                                        $options['optional'] = true;
                                } else {
                                        $options['optional'] = !empty( $options['optional'] );
index 1711aec..146470e 100644 (file)
@@ -10,6 +10,8 @@ class CreationReasonAuthenticationRequest extends AuthenticationRequest {
        /** @var string Account creation reason (only used when creating for someone else) */
        public $reason;
 
+       public $required = self::OPTIONAL;
+
        public function getFieldInfo() {
                return [
                        'reason' => [
index 84a0ea6..cac031c 100644 (file)
@@ -243,14 +243,6 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
 
                $req1->required = AuthenticationRequest::PRIMARY_REQUIRED;
 
-               $fields = AuthenticationRequest::mergeFieldInfo( [ $req1 ] );
-               $expect = $req1->getFieldInfo();
-               foreach ( $expect as $name => &$options ) {
-                       $options['optional'] = true;
-               }
-               unset( $options );
-               $this->assertEquals( $expect, $fields );
-
                $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
                $expect += $req2->getFieldInfo();
                $expect['string1']['optional'] = false;
@@ -258,6 +250,17 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
                $expect['select']['optional'] = false;
                $expect['select']['options']['bar'] = $msg;
                $this->assertEquals( $expect, $fields );
+
+               $req2->required = AuthenticationRequest::PRIMARY_REQUIRED;
+
+               $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
+               $expect = $req1->getFieldInfo() + $req2->getFieldInfo();
+               $expect['string1']['optional'] = false;
+               $expect['string2']['optional'] = true;
+               $expect['string3']['optional'] = true;
+               $expect['select']['optional'] = false;
+               $expect['select']['options']['bar'] = $msg;
+               $this->assertEquals( $expect, $fields );
        }
 
        /**