LoginController::renew()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
/**
3
 * Login controller class.
4
 *
5
 * @version 1.2.0
6
 * @since 1.2.0
7
 */
8
9
namespace Cassava\CAS\Controller;
10
11
use Cassava\CAS;
12
use Cassava\Plugin;
13
14
/**
15
 * Implements CAS login.
16
 *
17
 * Implements the `/login` URI and determines whether to interpret the request as a credential
18
 * requestor or a credential acceptor.
19
 *
20
 * @since 1.2.0
21
 */
22
class LoginController extends BaseController {
23
24
	/**
25
	 * Handles login requests.
26
	 *
27
	 * @param array $request Request arguments.
28
	 *
29
	 * @global $_POST
30
	 *
31
	 * @uses \apply_filters()
32
	 */
33
	public function handleRequest( $request ) {
0 ignored issues
show
Coding Style introduced by
handleRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
34
		$request = array_merge( $_POST, (array) $request );
35
36
		/**
37
		 * Allows developers to change the request parameters passed to a `/login` request.
38
		 *
39
		 * @param array $request HTTP request (GET, POST) parameters.
40
		 */
41
		$request = \apply_filters( 'cas_server_login_args', $request );
42
43
		if ( isset( $request['username'] ) && isset( $request['password'] ) && isset( $request['lt'] ) ) {
44
			$this->loginAcceptor( $request );
45
			return;
46
		}
47
48
		$this->loginRequestor( $request );
49
	}
50
51
	/**
52
	 * Implements the `/login` URI behaviour as credential acceptor when a set of accepted
53
	 * credentials are passed to `/login` via POST.
54
	 *
55
	 * This plugin does not implement a form to take advantage of this request behaviour, and relies
56
	 * on WordPress' own authentication interfaces. Developers may implement custom forms so long as
57
	 * they send the request parameters described below.
58
	 *
59
	 * The following HTTP request parameters MUST be passed to `/login` while it is acting as a
60
	 * credential acceptor for username/password authentication. They are all case-sensitive.
61
	 *
62
	 * - `username`: The username of the client that is trying to log in.
63
	 * - `password`: The password of the client that is trying to log in.
64
	 * - `lt`: A login ticket. It acts as a nonce to prevent replaying requests.
65
	 *
66
	 * The following HTTP request parameters are optional:
67
	 *
68
	 * - `service`: The URL of the application the client is trying to access. CAS will redirect the
69
	 *   client to this URL upon successful authentication.
70
	 * - `warn`: If this parameter is set, single sign-on will NOT be transparent. The client will
71
	 *   be prompted before being authenticated to another service.
72
	 *
73
	 * @param array $request Request arguments.
74
	 *
75
	 * @uses \is_wp_error()
76
	 * @uses \sanitize_user()
77
	 * @uses \wp_signon()
78
	 * @uses \wp_verify_nonce()
79
	 *
80
	 * @todo Support for the optional warn parameter.
81
	 */
82
	private function loginAcceptor( $request = array() ) {
83
84
		$username   = \sanitize_user( $request['username'] );
85
		$password   = $request['password'];
86
		$lt         = preg_replace( '@^' . CAS\Ticket::TYPE_LT . '-@', '', $request['lt'] );
87
		$service    = isset( $request['service'] ) ? $request['service'] : null;
88
89
		if ( ! \wp_verify_nonce( $lt, 'lt' ) ) {
90
			$this->server->authRedirect( $request );
91
		}
92
93
		$user = \wp_signon( array(
94
			'user_login'    => $username,
95
			'user_password' => $password,
96
		) );
97
98
		if ( ! $user || \is_wp_error( $user ) ) {
99
			$this->server->authRedirect( $request );
100
		}
101
102
		$this->login( $user, $service );
103
	}
104
105
	/**
106
	 * Implements the `/login` URI as credential requestor.
107
	 *
108
	 * If the client has already established a single sign-on session with CAS, the
109
	 * client will have presented its HTTP session cookie to `/login` unless the "renew"
110
	 * parameter is set to "true".
111
	 *
112
	 * If there is no session or the "renew" parameter is set, CAS will respond by
113
	 * displaying a login screen requesting (usually) a username and password.
114
	 *
115
	 * @param array $request Request arguments.
116
	 *
117
	 * @uses \is_user_logged_in()
118
	 * @uses \wp_get_current_user()
119
	 */
120
	private function loginRequestor( $request = array() ) {
121
122
		$this->server->sessionStart();
123
124
		$renew   = isset( $request['renew'] )   && 'true' === $request['renew'];
125
		$gateway = isset( $request['gateway'] ) && 'true' === $request['gateway'];
126
		$service = isset( $request['service'] ) ? $request['service'] : '';
127
128
		if ( $renew ) {
129
			$this->renew();
130
		}
131
132
		if ( ! \is_user_logged_in() ) {
133
			if ( $gateway && $service ) {
134
				$this->server->redirect( $service );
135
			}
136
137
			$this->server->authRedirect( $request );
138
		}
139
140
		$this->login( \wp_get_current_user(), $service );
141
	}
142
143
	/**
144
	 * Renews the user session.
145
	 *
146
	 * Invalidates the user session and repeats the login request without the
147
	 * `renew` parameter.
148
	 *
149
	 * @uses \is_ssl()
150
	 * @uses \remove_query_arg()
151
	 * @uses \wp_logout()
152
	 */
153
	private function renew() {
0 ignored issues
show
Coding Style introduced by
renew uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
154
		\wp_logout();
155
156
		$schema = \is_ssl() ? 'https://' : 'http://';
157
		$url    = $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
158
		$url    = \remove_query_arg( 'renew', $url );
159
160
		$this->server->redirect( $url );
161
	}
162
163
	/**
164
	 * Logs the user in.
165
	 *
166
	 * @param \WP_User $user    WordPress user to authenticate.
167
	 * @param string   $service URI for the service requesting user authentication.
168
	 *
169
	 * @uses \add_query_arg()
170
	 * @uses \apply_filters()
171
	 * @uses \esc_url_raw()
172
	 * @uses \home_url()
173
	 */
174
	private function login( $user, $service = '' ) {
175
		$ticket = new CAS\Ticket( CAS\Ticket::TYPE_ST, $user, $service );
176
177
		$service = empty( $service ) ? \home_url() : \esc_url_raw( $service );
178
		$service = \add_query_arg( 'ticket', (string) $ticket, $service );
179
180
		/**
181
		 * Filters the redirect URI for the service requesting user authentication.
182
		 *
183
		 * @param  string  $service Service URI requesting user authentication.
184
		 * @param  WP_User $user    Logged in WordPress user.
185
		 */
186
		$service = \apply_filters( 'cas_server_redirect_service', $service, $user );
187
188
		$this->server->redirect( $service );
189
	}
190
}
191