Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Client isn't challenged when authentication is set in map but no Authorization header is sent #101

Open
VOONWerbeagentur opened this issue Sep 24, 2015 · 2 comments

Comments

@VOONWerbeagentur
Copy link

I'm facing the situation, that the API client isn't challenged when authorization is required for a service and no Authorization header is given:

my config:

return array(
    'zf-mvc-auth' => array(
        'authentication' => array(
            'map' => array(
                'MyService\\V1' => 'http_digest',
            ),
            'adapters' => array(
                'http_digest' => array(
                    'adapter' => 'ZF\\MvcAuth\\Authentication\\HttpAdapter',
                    'options' => array(
                        'accept_schemes' => array(
                            0 => 'digest',
                        ),
                        'realm' => 'MDM',
                        'digest_domains' => '/my-service',
                        'nonce_timeout' => '3600',
                        'htdigest' => 'data/users.htdigest',
                    ),
                ),
            ),
        ),
        'authorization' => array(
            'deny_by_default' => false,
        ),
    ),
);

Sending the following request, should challange the client, but the server does not include a WWW-Authenticate header in its response:

> GET /my-service/my-action HTTP/1.1
> Host: localhost
> User-Agent: curl/7.43.0
> Accept: application/json
> 
< HTTP/1.1 403 Forbidden
< Date: Thu, 24 Sep 2015 15:22:55 GMT
< Server: Apache/2.4.16 (Unix) PHP/5.5.23
< X-Powered-By: PHP/5.5.23
< Vary: Accept-Encoding,User-Agent
< Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
< Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
< Access-Control-Allow-Origin: *
< Access-Control-Max-Age: 1000
< Content-Length: 119
< Content-Type: application/problem+json

I've identified the following section in ZF\MvcAuth\Authentication\DefaultAuthenticationListener's __invoke function responsible for not challenging the client:

        $type = $this->getTypeFromMap($mvcEvent->getRouteMatch());
        if (false === $type && count($this->adapters) > 1) {
            // Ambiguous situation; no matching type in map, but multiple
            // authentication adapters; return a guest identity.
            $identity = new Identity\GuestIdentity();
            $mvcEvent->setParam('ZF\MvcAuth\Identity', $identity);
            return $identity;
        }

        $type = $type ?: $this->getTypeFromRequest($request);
        if (false === $type) {
            // No authentication type known; trigger any pre-flight actions,
            // and return a guest identity.
            $this->triggerAdapterPreAuth($request, $response);
            $identity = new Identity\GuestIdentity();
            $mvcEvent->setParam('ZF\MvcAuth\Identity', $identity);
            return $identity;
        }

        // Authenticate against first matching adapter
        $identity = $this->authenticate($type, $request, $response, $mvcAuthEvent);

        // If the adapter returns a response instance, return it directly.
        if ($identity instanceof HttpResponse) {
            return $identity;
        }

        // If no identity returned, create a guest identity
        if (! $identity instanceof Identity\IdentityInterface) {
            $identity = new Identity\GuestIdentity();
        }

Changing it like this, the client is at least challenged when no credentials are submitted:

        $type = $this->getTypeFromMap($mvcEvent->getRouteMatch());
        if (false === $type && count($this->adapters) > 1) {
            // Ambiguous situation; no matching type in map, but multiple
            // authentication adapters; return a guest identity.
            $identity = new Identity\GuestIdentity();
            $mvcEvent->setParam('ZF\MvcAuth\Identity', $identity);
            return $identity;
        }

        $typeFromRequest = $this->getTypeFromRequest($request);
        $type = $typeFromRequest ? "{$type}-{$typeFromRequest}" : false;

        if (false === $type) {
            // No authentication type known; trigger any pre-flight actions,
            // and return a guest identity.
            $this->triggerAdapterPreAuth($request, $response);
            $identity = new Identity\GuestIdentity();
            $mvcEvent->setParam('ZF\MvcAuth\Identity', $identity);
            return $identity;
        }

        // Authenticate against first matching adapter
        $identity = $this->authenticate($type, $request, $response, $mvcAuthEvent);

        // If the adapter returns a response instance, return it directly.
        if ($identity instanceof HttpResponse) {
            return $identity;
        }

        // If no identity returned, create a guest identity
        if (! $identity instanceof Identity\IdentityInterface) {
            $identity = new Identity\GuestIdentity();
        }
@MassiAtZend
Copy link

The solution offered above indeed triggers the Digest challenge, it is not complete though as the response is not an API problem with status 401, but a successful one with data in the body.

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas-api-tools/api-tools-mvc-auth; a new issue has been opened at laminas-api-tools/api-tools-mvc-auth#12.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants