Completed
Push — master ( 664d98...03ed01 )
by Thomas
11:36
created

TokenAuthModule::getTokenForAppPassword()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 6
nop 2
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Thomas Müller <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2018, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
23
namespace OC\User;
24
25
26
use OC\Authentication\Exceptions\InvalidTokenException;
27
use OC\Authentication\Exceptions\PasswordlessTokenException;
28
use OC\Authentication\Token\IProvider;
29
use OC\Authentication\Token\IToken;
30
use OCP\Authentication\IAuthModule;
31
use OCP\IRequest;
32
use OCP\ISession;
33
use OCP\IUser;
34
use OCP\IUserManager;
35
use OCP\Session\Exceptions\SessionNotAvailableException;
36
37
class TokenAuthModule implements IAuthModule {
38
39
	/** @var ISession */
40
	private $session;
41
42
	/** @var IProvider */
43
	private $tokenProvider;
44
45
	/** @var IUserManager */
46
	private $manager;
47
48
	/** @var string */
49
	private $password = '';
50
51
	public function __construct(ISession $session, IProvider $tokenProvider, IUserManager $manager) {
52
		$this->session = $session;
53
		$this->tokenProvider = $tokenProvider;
54
		$this->manager = $manager;
55
	}
56
57
	/**
58
	 * @inheritdoc
59
	 */
60
	public function auth(IRequest $request) {
61
		$dbToken = $this->getTokenForAppPassword($request, $token);
62
		if ($dbToken === null) {
63
			$dbToken = $this->getToken($request, $token);
64
		}
65
		if ($dbToken === null) {
66
			return null;
67
		}
68
69
		// When logging in with token, the password must be decrypted first before passing to login hook
70
		try {
71
			$this->password = $this->tokenProvider->getPassword($dbToken, $token);
72
		} catch (PasswordlessTokenException $ex) {
73
			// Ignore and use empty string instead
74
		}
75
76
		$uid = $dbToken->getUID();
77
		return $this->manager->get($uid);
78
	}
79
80
	/**
81
	 * @inheritdoc
82
	 */
83
	public function getUserPassword(IRequest $request) {
84
		return $this->password;
85
	}
86
87
	/**
88
	 * @param IRequest $request
89
	 * @return null|IToken
90
	 */
91
	private function getTokenForAppPassword(IRequest $request, &$token) {
92
		if (!isset($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'])) {
0 ignored issues
show
Bug introduced by
Accessing server on the interface OCP\IRequest suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
93
			return null;
94
		}
95
96
		try {
97
			$token = $request->server['PHP_AUTH_PW'];
0 ignored issues
show
Bug introduced by
Accessing server on the interface OCP\IRequest suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
98
			$dbToken = $this->tokenProvider->getToken($token);
99
			if ($dbToken->getUID() !== $request->server['PHP_AUTH_USER']) {
0 ignored issues
show
Bug introduced by
Accessing server on the interface OCP\IRequest suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
100
				throw new \Exception('Invalid credentials');
101
			}
102
103
			return $dbToken;
104
		} catch (InvalidTokenException $ex) {
105
			// invalid app passwords do NOT throw an exception because basic
106
			// auth headers can be evaluated properly in the basic auth module
107
			$token = null;
108
			return null;
109
		}
110
	}
111
112
	/**
113
	 * @param IRequest $request
114
	 * @return null|IToken
115
	 * @throws \Exception
116
	 */
117
	private function getToken(IRequest $request, &$token) {
118
		$authHeader = $request->getHeader('Authorization');
119 View Code Duplication
		if ($authHeader === null || strpos($authHeader, 'token ') === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
120
			// No auth header, let's try session id
121
			try {
122
				$token = $this->session->getId();
123
			} catch (SessionNotAvailableException $ex) {
124
				return null;
125
			}
126
		} else {
127
			$token = substr($authHeader, 6);
128
		}
129
130
		try {
131
			return $this->tokenProvider->getToken($token);
132
		} catch (InvalidTokenException $ex) {
133
			$token = null;
134
			return null;
135
		}
136
	}
137
}
138