1
|
|
|
<?php
|
2
|
|
|
|
3
|
|
|
namespace Azine\HybridAuthBundle\Controller;
|
4
|
|
|
|
5
|
|
|
use Symfony\Component\HttpFoundation\ParameterBag;
|
6
|
|
|
|
7
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
8
|
|
|
|
9
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
10
|
|
|
|
11
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
12
|
|
|
|
13
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
14
|
|
|
|
15
|
|
|
class HybridEndPointController extends Controller {
|
16
|
|
|
|
17
|
|
|
private $initDone = FALSE;
|
18
|
|
|
/**
|
19
|
|
|
* @var \Hybrid_Auth
|
20
|
|
|
*/
|
21
|
|
|
private $hybridAuth;
|
22
|
|
|
|
23
|
|
|
/**
|
24
|
|
|
* @var ParameterBag
|
25
|
|
|
*/
|
26
|
|
|
private $requestQuery;
|
27
|
|
|
|
28
|
|
|
/**
|
29
|
|
|
* Process the current request
|
30
|
|
|
*
|
31
|
|
|
* $request - The current request parameters. Leave as NULL to default to use $_REQUEST.
|
32
|
|
|
* @param Request $request
|
33
|
|
|
* @return RedirectResponse|Response
|
34
|
|
|
*/
|
35
|
|
|
public function processAction(Request $request) {
|
36
|
|
|
// Get the request Vars
|
37
|
|
|
$this->requestQuery = $request->query;
|
38
|
|
|
|
39
|
|
|
// init the hybridAuth instance
|
40
|
|
|
$provider = trim( strip_tags( $this->requestQuery->get("hauth_start") ) );
|
41
|
|
|
$cookieName = $this->get("azine_hybrid_auth_service")->getCookieName($provider);
|
42
|
|
|
$this->hybridAuth = $this->get("azine_hybrid_auth_service")->getInstance($request->cookies->get($cookieName), $provider);
|
43
|
|
|
|
44
|
|
|
// If openid_policy requested, we return our policy document
|
45
|
|
|
if ( $this->requestQuery->has('get') && $this->requestQuery->get('get') == "openid_policy" ) {
|
46
|
|
|
return $this->processOpenidPolicy();
|
|
|
|
|
47
|
|
|
}
|
48
|
|
|
|
49
|
|
|
// If openid_xrds requested, we return our XRDS document
|
50
|
|
|
if ( $this->requestQuery->has('get') && $this->requestQuery->get('get') == "openid_xrds" ) {
|
51
|
|
|
return $this->processOpenidXRDS();
|
52
|
|
|
}
|
53
|
|
|
|
54
|
|
|
// If we get a hauth.start
|
55
|
|
|
if ( $this->requestQuery->has('hauth_start') && $this->requestQuery->get('hauth_start') ) {
|
56
|
|
|
return $this->processAuthStart();
|
57
|
|
|
}
|
58
|
|
|
// Else if hauth.done
|
59
|
|
|
elseif ( $this->requestQuery->has('hauth_done') && $this->requestQuery->get('hauth_done') ) {
|
60
|
|
|
return $this->processAuthDone($request);
|
61
|
|
|
}
|
62
|
|
|
// Else we advertise our XRDS document, something supposed to be done from the Realm URL page
|
63
|
|
|
else {
|
64
|
|
|
return $this->processOpenidRealm();
|
65
|
|
|
}
|
66
|
|
|
}
|
67
|
|
|
|
68
|
|
|
/**
|
69
|
|
|
* Process OpenID policy request
|
70
|
|
|
*/
|
71
|
|
|
private function processOpenidPolicy() {
|
72
|
|
|
$output = file_get_contents( dirname(__FILE__) . "/resources/openid_policy.html" );
|
73
|
|
|
return $output;
|
74
|
|
|
}
|
75
|
|
|
|
76
|
|
|
/**
|
77
|
|
|
* Process OpenID XRDS request
|
78
|
|
|
*/
|
79
|
|
|
private function processOpenidXRDS() {
|
80
|
|
|
header("Content-Type: application/xrds+xml");
|
81
|
|
|
|
82
|
|
|
$output = str_replace
|
83
|
|
|
(
|
84
|
|
|
"{RETURN_TO_URL}",
|
85
|
|
|
str_replace(
|
86
|
|
|
array("<", ">", "\"", "'", "&"), array("<", ">", """, "'", "&"),
|
87
|
|
|
$this->hybridAuth->getCurrentUrl( false )
|
88
|
|
|
),
|
89
|
|
|
file_get_contents( dirname(__FILE__) . "/resources/openid_xrds.xml" )
|
90
|
|
|
);
|
91
|
|
|
return new Response($output);
|
92
|
|
|
}
|
93
|
|
|
|
94
|
|
|
/**
|
95
|
|
|
* Process OpenID realm request
|
96
|
|
|
*/
|
97
|
|
|
private function processOpenidRealm() {
|
98
|
|
|
|
99
|
|
|
$output = str_replace
|
100
|
|
|
(
|
101
|
|
|
"{X_XRDS_LOCATION}",
|
102
|
|
|
htmlentities( $this->hybridAuth->getCurrentUrl( false ), ENT_QUOTES, 'UTF-8' ) . "?get=openid_xrds&v=" . \Hybrid_Auth::$version,
|
103
|
|
|
file_get_contents( dirname(__FILE__) . "/resources/openid_realm.html" )
|
104
|
|
|
);
|
105
|
|
|
return new Response($output);
|
106
|
|
|
}
|
107
|
|
|
|
108
|
|
|
/**
|
109
|
|
|
* define:endpoint step 3.
|
110
|
|
|
*/
|
111
|
|
|
private function processAuthStart() {
|
112
|
|
|
|
113
|
|
|
$response = $this->authInit();
|
114
|
|
|
if($response instanceof Response){
|
115
|
|
|
return $response;
|
116
|
|
|
}
|
117
|
|
|
|
118
|
|
|
$provider_id = trim( strip_tags( $this->requestQuery->get("hauth_start") ) );
|
119
|
|
|
|
120
|
|
|
# check if page accessed directly
|
121
|
|
|
if( ! $this->hybridAuth->storage()->get( "hauth_session.$provider_id.hauth_endpoint" ) ) {
|
122
|
|
|
\Hybrid_Logger::error( "Endpoint: hauth_endpoint parameter is not defined on hauth_start, halt login process!" );
|
123
|
|
|
|
124
|
|
|
return new Response("You cannot access this page directly.", 404, array(header( "HTTP/1.0 404 Not Found" )));
|
125
|
|
|
}
|
126
|
|
|
|
127
|
|
|
# define:hybrid.endpoint.php step 2.
|
128
|
|
|
$hauth = $this->hybridAuth->setup( $provider_id );
|
129
|
|
|
|
130
|
|
|
# if REQUESTed hauth_idprovider is wrong, session not created, etc.
|
131
|
|
|
if( ! $hauth ) {
|
132
|
|
|
\Hybrid_Logger::error( "Endpoint: Invalid parameter on hauth_start!" );
|
133
|
|
|
|
134
|
|
|
return new Response("Invalid parameter! Please return to the login page and try again.", 404, array(header( "HTTP/1.0 404 Not Found" )));
|
135
|
|
|
}
|
136
|
|
|
|
137
|
|
|
try {
|
138
|
|
|
\Hybrid_Logger::info( "Endpoint: call adapter [{$provider_id}] loginBegin()" );
|
139
|
|
|
|
140
|
|
|
$hauth->adapter->loginBegin();
|
141
|
|
|
}
|
142
|
|
|
catch ( \Exception $e ) {
|
143
|
|
|
$logger = $this->get("logger");
|
144
|
|
|
$logger->error("Exception: Code: " . $e->getCode() . "; Message: " . $e->getMessage(), $e->getTrace());
|
145
|
|
|
if($e->getPrevious() != null && $e->getPrevious() != $e){
|
146
|
|
|
$p = $e->getPrevious();
|
147
|
|
|
$logger->error("Exception: Code: " . $p->getCode() . "; Message: " . $p->getMessage(), $p->getTrace());
|
148
|
|
|
}
|
149
|
|
|
// replace the callback_url with the referrer.
|
150
|
|
|
if(isset($_SERVER['HTTP_REFERER'])){
|
151
|
|
|
$this->hybridAuth->storage()->set( "hauth_session.$provider_id.hauth_return_to", $_SERVER['HTTP_REFERER'] );
|
152
|
|
|
} else {
|
153
|
|
|
// or go back in the browser-history via js
|
154
|
|
|
return new Response("<html><body onload='window.history.back();'><h1>An Error occured.</h1>Going back one step in the browser history.</body></html>", 500);
|
155
|
|
|
}
|
156
|
|
|
}
|
157
|
|
|
return $this->returnToCallbackUrl($provider_id);
|
158
|
|
|
}
|
159
|
|
|
|
160
|
|
|
/**
|
161
|
|
|
* define:endpoint step 3.1 and 3.2
|
162
|
|
|
*/
|
163
|
|
|
private function processAuthDone(Request $request) {
|
164
|
|
|
|
165
|
|
|
$this->authInit();
|
166
|
|
|
|
167
|
|
|
$provider_id = trim( strip_tags( $this->requestQuery->get("hauth_done") ) );
|
168
|
|
|
|
169
|
|
|
$hauth = $this->hybridAuth->setup( $provider_id );
|
170
|
|
|
|
171
|
|
|
$authCookie = null;
|
172
|
|
|
|
173
|
|
|
if( ! $hauth ) {
|
174
|
|
|
\Hybrid_Logger::error( "Endpoint: Invalid parameter on hauth_done!" );
|
175
|
|
|
|
176
|
|
|
$hauth->adapter->setUserUnconnected();
|
177
|
|
|
|
178
|
|
|
return new Response("Invalid parameter! Please return to the login page and try again.", 404, array(header( "HTTP/1.0 404 Not Found" )));
|
179
|
|
|
}
|
180
|
|
|
|
181
|
|
|
try {
|
182
|
|
|
\Hybrid_Logger::info( "Endpoint: call adapter [{$provider_id}] loginFinish() " );
|
183
|
|
|
|
184
|
|
|
$hauth->adapter->loginFinish();
|
185
|
|
|
|
186
|
|
|
// store auth-session-data
|
187
|
|
|
$authCookie = $this->get("azine_hybrid_auth_service")->storeHybridAuthSessionData($request, $provider_id, $this->hybridAuth->getSessionData());
|
188
|
|
|
}
|
189
|
|
|
catch( \Exception $e ){
|
190
|
|
|
\Hybrid_Logger::error( "Exception:" . $e->getMessage()."\n\n".$e->getTraceAsString() );
|
191
|
|
|
\Hybrid_Error::setError( $e->getMessage(), $e->getCode(), $e->getTraceAsString(), $e->getPrevious());
|
192
|
|
|
|
193
|
|
|
$hauth->adapter->setUserUnconnected();
|
194
|
|
|
|
195
|
|
|
}
|
196
|
|
|
|
197
|
|
|
\Hybrid_Logger::info( "Endpoint: job done. retrun to callback url." );
|
198
|
|
|
|
199
|
|
|
$response = $this->returnToCallbackUrl($provider_id);
|
200
|
|
|
|
201
|
|
|
// add auth-session-data into cookie
|
202
|
|
|
if($authCookie){
|
203
|
|
|
$response->headers->setCookie($authCookie);
|
204
|
|
|
}
|
205
|
|
|
return $response;
|
206
|
|
|
}
|
207
|
|
|
|
208
|
|
|
private function authInit() {
|
209
|
|
|
|
210
|
|
|
if ( ! $this->initDone) {
|
211
|
|
|
$this->initDone = TRUE;
|
212
|
|
|
|
213
|
|
|
# Init Hybrid_Auth
|
214
|
|
|
try {
|
215
|
|
|
if(!class_exists("Hybrid_Storage")){
|
216
|
|
|
require_once realpath( dirname( __FILE__ ) ) . "/Storage.php";
|
217
|
|
|
}
|
218
|
|
|
|
219
|
|
|
$storage = new \Hybrid_Storage();
|
220
|
|
|
|
221
|
|
|
// Check if Hybrid_Auth session already exist
|
222
|
|
|
if ( ! $storage->config( "CONFIG" ) ) {
|
223
|
|
|
return new Response("You cannot access this page directly.", 500, array(header( "HTTP/1.0 500 Server Error" )));
|
224
|
|
|
}
|
225
|
|
|
|
226
|
|
|
$this->hybridAuth->initialize( $storage->config( "CONFIG" ) );
|
227
|
|
|
}
|
228
|
|
|
catch ( \Exception $e ){
|
229
|
|
|
\Hybrid_Logger::error( "Endpoint: Error while trying to init Hybrid_Auth" );
|
230
|
|
|
|
231
|
|
|
return new Response("Oophs. Error!", 500, array(header( "HTTP/1.0 500 Server Error" )));
|
232
|
|
|
}
|
233
|
|
|
}
|
234
|
|
|
}
|
235
|
|
|
|
236
|
|
|
private function returnToCallbackUrl($provider_id) {
|
237
|
|
|
// get the stored callback url
|
238
|
|
|
$callback_url = $this->hybridAuth->storage()->get( "hauth_session.$provider_id.hauth_return_to" );
|
239
|
|
|
|
240
|
|
|
// remove some unneeded stored data
|
241
|
|
|
$this->hybridAuth->storage()->delete( "hauth_session.$provider_id.hauth_return_to" );
|
242
|
|
|
$this->hybridAuth->storage()->delete( "hauth_session.$provider_id.hauth_endpoint" );
|
243
|
|
|
$this->hybridAuth->storage()->delete( "hauth_session.$provider_id.id_provider_params" );
|
244
|
|
|
|
245
|
|
|
// back to home
|
246
|
|
|
return new RedirectResponse($callback_url);
|
247
|
|
|
}
|
248
|
|
|
|
249
|
|
|
}
|
250
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.