I am new to CakePHP and am using version 2.7.5.
I followed the tutorial to create a basic REST service.
I now secured them using the basic auth tutorial.
Now, I have an AngularJS app over this REST service but need a way to prompt users to login or say their account does not have access to that resource.
Right now, when the REST call is made, and they do not have access, the response is a redirect HTML page to "/" or to logon. But I want the response in JSON with a message that says "access denied" or "session is up please logon.." etc.
I know it's the flash variable in cakephp but i am using AngularJS.
So my question is, where do I code in cakephp to send json response instead of HTML page redirect if a user does not have access to a certain rest url after logging in?
You can just return a response header back to the request with the correct status code(401).
if(!$authorized){
return header('HTTP/1.0 401 Unauthorized');
}
You can catch the error code in your request method, for example an ajax request
.error(status){
switch(status.code)
{
case 401:
//Unauthorized
break;
}
}
Related
I have a php application that accesses Asana API. I am able to create a project in Asana. However, the ajax call to the API class is returning a readystate=0.
While troubleshooting in firebug I also noticed that the network console has a 302, 400(??), and 200 status code. I thought 400 status code is related to invalid request or malformed url, but the project gets created anyway.
Any idea?
Update: More information.
I have a Ajax call to a php file which intern calls Asana API to getAuth code and tokens before calling the API services.
I believe I am getting the CORS warning and hence the readystate=0 and the 400 error. However because rest of my script proceeds with the token it was inserting records anyways. However, after the tokens expired (3600 sec), now I am unable to insert records. I know if I call the php file directly it works without the CORS error.
$.ajax({
type: 'POST',
url: "oa/asana.php",
data: {apiprovider:"asana",type:"addnewproject",notes:"notes",name:"name",id:"id",resource:"projects"},
//dataType:"json",
//contentType: "application/json",
success: function(data) {
console.log(data);
},
error: function( error )
{
console.log("asana api error");
console.log(JSON.stringify(error)) ;
},
async:true
});
my php code looks like this.
...$asana = new AsanaAuth(API_KEY,API_SECRET,callbackUrl);
if (!isset($_GET['code'])) {
$url = $asana->getAuthorizeUrl();
header('Location:' . $url);
} else {
$asana->getAccessToken($_GET['code']);
if ($asana->hasError()) {
echo 'Error response code: ' . $asana->responseCode;
}
else {
echo $asana->response;
}
}
Is there a better way to do this outside of Ajax call?
OK here's how I fixed it. Partly my understanding was wrong and I made a wrong assumption.
This is purely based on my application's need and this may not be applicable to all.
I have a settings page where the user clicks on the Asana app to authorize the connection. This is not a Ajax call but a hyperlink to a file which is also my redirect uri. Within this file I check if the user has already authorized if not I call authorize, get tokens and store the refresh token in the database for future use.
In the other parts of my application, when the user clicks on create an asana project, I check for the validity of the access token if it has expired, I refresh and get another token again.
Earlier, I was trying to call this from one page (which in a normal user flow will never happen -in my application). So right now there is no Ajax call for authorize but calling the refresh token, and Asana API endpoints are through Ajax and they work fine.
Hope this helps someone in future.
I am currently working on a project that I've decided to go with basic HTTP authorization at the admin area for simplicity, however the company I'm working for already has HTTP authorization on their staging server and I was wondering if it is possible to have double HTTP authorization? Looking at the headers I thought that the realm part is what defines where the user is authorized but if I implement it like that currently, after I enter my credentials for the staging server and then on my inner authorization something that looks like an infinite loop starts, the page never loads.
Is this possible at all or is there some kind of error in my code?
The code is pretty basic stuff:
function require_auth() {
if (!isset($_SESSION['auth'])) {
if ($_SERVER['PHP_AUTH_USER'] === '...' && $_SERVER['PHP_AUTH_PW'] === '...') {
return $_SESSION['auth'] = true;
} else {
header('WWW-Authenticate: Basic realm="uniquerealm"');
header('HTTP/1.0 401 Unauthorized');
}
exit('403 access denied');
}
}
If the HTTP request passes through multiple servers, such as a reverse proxy then an app server, you can use HTTP Basic Auth on each server provided that you accept the same username and password and report the same realm on each server that checks the auth. The realm partitions the URL space that the user sees into different areas, rather than identifying a particular server as I think your question is implying. I've successfully implemented Basic Auth in multiple layers in the past when all 3 pieces matched between servers.
Using python httpx_auth, I successfully passed through two Basic HTTP Authentication with different credentials:
import httpx
from httpx_auth import Basic
with httpx.Client() as client:
a= client.get('https://example.com', auth=Basic('user1', 'password1') + Basic('user2','password2'))
I am trying to authenticate with a family history web service that authenticates using OAuth2. The basic workflow of the authentication is that I submit a get request against the web service requesting an authentication session. It returns in the body of the response HTML Code with some login components for user name and password. My PHP application then echoes the html code to the browser. The end user can then enter his or her user name and password, then submit to the web service. This is where the behavior becomes unclear. In theory, The web service should redirect to a predefined redirect URI with some parameters included in the URL. In practice, however, submitting the password redirects to the pre registered redirect URI, but there are no parameters included in the URL. My Project is written primarily in PHP. This is a snippit of the code that makes the inital request for an authentication session.
function logOn($mainURL, $credentials)
{
// create a new HTTP_Request object to be used in the login process
$request = new HTTP_Request();
// set the URL of the HTTP_Request object to the family search identity/login endpoint
$request->setUrl("https://web-service/authentication/path?response_type=code&client_id=".$credentials['key']."&redirect_uri=https://www.myredirectPage.edu/");
$request->_useBrackets = false;
$request->addHeader("User-Agent", $credentials['agent']);
$request->addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
$request->sendRequest();
//HTML_HEADER;
//the response will come in the form of an html file
$responseHtml = $request->getResponseBody();
//Dynamically load html from request body onto the browser to allow for authentication
echo $responseHtml;
return $credentials;
}
The end user will enter their login credentials using the loaded html components and hit submit. The web service then redirects to my redirect authentication page. The code there is provided below.
<?php
// process client request (Via url)
//gather code parameters from the redirect url.
if (isset($_GET['code']))
{
echo $_GET['code'];
}
else
{
echo "code not returned";
}
if (isset($_GET['error']))
{
echo $_GET['error'];
}
else
{
echo "error not returned";
}
?>
Thanks in advance to any help with this.
When I use Google Chrome's Network debugger tool, I saw that my project was making unexpected searches for Javascript and Css resources, all resulting in 404 (not found) errors. Upon closer inspection, I could see that the resources were relative paths to resources that are on the web service server. Rather than looking for 'https://webService.net/js/importantJavascript.js' (an existing file located on the service's web server), it was trying to find 'https://mywebpage.edu/js/importantJavascript.js'(a path to a file that doesn't exist).
I'm getting google api authorization code from this page on my server
https://github.com/google/google-api-php-client/blob/master/examples/user-example.php
the same page on my hosting to test
http://mawk3y.net/google/google-api-php-client/examples/user-example.php
after adjusting client id, secret and redirect uri.
$data =file_get_contents('https://accounts.google.com/o/oauth2/auth?code='.$code.'&client_secret={secret}&redirect_uri={my web page}&grant_type=authorization_code');
print_r($data);
but i get an error so i'm trying to paste the full url to the browser address bar after getting authorization code from that page like this (the same auth code I get from this page https://developers.google.com/oauthplayground/)
https://accounts.google.com/o/oauth2/token?code={authorization code}&redirect_uri=mywebpage.php&client_id={my client id}&client_secret={secret code}&grant_type=authorization_code
but the result is
{
"error" : "invalid_request"
}
how to solve this and exchange the authorization code for access token
You're sending the parameters in a GET request to the authorization endpoint (https://accounts.google.com/o/oauth2/auth), but you must send them in a POST request to the token endpoint (https://accounts.google.com/o/oauth2/token).
When you use basic auth filter in Laravel 4.2, I noticed that you can't set the realm (maybe just me?) for the authentication, and therefore when the auth window appears, it looks like this in internet explorer:
Take a look at the official documentation example : http://php.net/manual/en/features.http-auth.php#example-372
If I had used this, the above login window will say Restricted area rather than null.
Any idea how to set the realm of basic auth in Laravel?
Also, how or where do you set/style the text to display when the auth fails or user hits the cancel button?
Found that, but nothing laravelish.
header('WWW-Authenticate: Basic realm="REALM"');
header('HTTP/1.0 401 Unauthorized');
Use the following route filter :
Route::filter('auth.basic', function() {
$response = Auth::basic();
if (!is_null($response)) {
return $response->header("WWW-Authenticate", 'Basic realm="REALM"');
}
});
Adapted from this answer which explains how it works in detail; basically Auth::basic() returns either null if the user is already authenticated or a 401 Unauthorized response with a WWW-Authenticate header, if the response isn't null we call the header method on that Response to replace that header with our custom version of WWWi-Authenticate including the realm parameter; if you look at that method you'll notice that it's set to replace any previous headers by default.
Finally the return value of that method is the response object itself so we can return that instead of explicitly returning $response on a new line.