How to bypass the login screen in a CakePHP app (jSlate)? - cakephp

I'm having problems integrating a CakePHP app (jSlate) into a bespoke non-Cake web application. All the alternative authentication scripts I've seen simply change the behaviour of the login form, in other words the login form still appears, and asks for username and password, but these are authenticated against an alternative source, such as LDAP.
What I actually want is for no login screen to appear at all. Instead I want a very simple behaviour:
Detect if user is already logged in to third party app.
If yes, automatically log them in to the CakePHP app (in this case jSlate).
If no, redirect to the third party app login screen.
Is there a tutorial for a CakePHP authentication along these lines? Or does someone know how to do this? I've worked out how to do part 3, but this behaviour is kind of useless without parts 1 and 2...

You can put this into your AppController::beforeFilter:
public function beforeFilter() {
if (!$this->Auth->user()) {
// if no user is currently logged in
if ($this->Cookie->read(...)) {
// or
if ($_COOKIE[...]) {
// or whatever else you want to detect
$this->redirect('http://some.external/login/service');
}
}
}
This external login service would then presumably redirect the user back to your Cake app at some point with some sort of token. You just need to define a publicly accessible action (no auth required) which it can redirect back to. In that action, you check all the tokens you need and can then "manually" authenticate the user:
$user = $this->User->find(/* find your Cake user by some id */);
if ($user) {
$this->Auth->login($user['User']['id']);
}
Congratulations, the user is now logged in as if he'd used a login form and has a valid Cake session.

Related

Custom React GUI for oidc-client-js

is there a way to user your custom React GUI with oidc-client-js? I know that if you trigger authentication endpoint using:
// PopUps might be blocked by the user, fallback to redirect
try {
await this.userManager.signinRedirect(this.createArguments(state)); //Shows midleware login form
return this.redirect();
} catch (redirectError) {
console.log("Redirect authentication error: ", redirectError);
return this.error(redirectError);
}
Middleware will try to render its predefined login form:
However I have my own React form and I only need to pass to OICDClient params (email,password) and get back User instance to display UserName etc. Something like:
var loggedUser = await this.userManager.signinCustom(state.loginEmail, state.LoginPassword); //Login using credentials
I don't want to write all the logic by myself I really want to use all functionality from OIDCClient - only with my GUI (loginForm, registerForm, updateUserForm etc).
I'm using scaffolded library from MSDN using command:
dotnet new react -o <output_directory_name> -au Individual
Is there any method/implementation to initialise oidc-client-js from React components and not user default GUI forms?
Thanks a lot!
I might be missing some thing but the whole idea of using a 3rd partly federated auth provider be it your own/your company's SSO (say developed using Identity Server 4) or say Google sign in(say using their Firebase JS kit) or Microsoft sign in, Facebook sign in etc. is that you will be redirected to their authentication endpoint where you then use say your google credentials (if you are using google sign in for example) to sign on to google auth servers. Once you do that then a payload (consisting of an identity token and access token) is returned back to your redirect URL which you must configure for your specific app.
By saying you'd like to provide your own sign-in form you are missing the entire point of using a 3rd party authentication provider. Besides, you/your app shouldn't know about user names and passwords and you don't want to have access to all that information. All that you should be interested in knowing whether the user, who are using one of the federated authentication providers, that you would have configured for your app, are who they claim to be and you then delegate all that heavy lifting to your 3rd party authentication provider.
Besides, say your company has a SSO system of their own then all your company's app will use that SSO system and from a UI perspective you want to show the same login screen so as to give a consistent user experience.
In addition, if you show me a google authentication button and then on clicking that button you show me some weird form that doesn't look like the typical google picklist sign-in form then I'll shut down your app before you can say hello, and, I suspect most user would (and should) do the same. The reason being that when you show me a google sign-in page then I know that you/your app will only get back what you need and I wouldn't ever entrust my google user name and password to any other application.
If you really want to have your own authentication form then you'll have to manage user names and passwords yourself, the way we used to do things probably over 10+ years back.
If you decide to go the route of setting up your own authentication system and then say use identity server 4 then yes you can certainly change the UI and customize it to your heart's content, but that will happen at the server level, not at the level of your react app. Point being that in any SSO system the user will be redirected to the that auth provider's endpoint where they then authenticate (and, optionally, provider permission for your app to use certain claims) and once they do that they they are redirected back to your redirect endpoint with a payload (JWT token).
Lastly, even if you could some how wire up a client side sign in form, I'm not sure you would want to use it. Passing passwords & user names over the wire isn't a good idea. You'll always want to use a server rendered sign in form.

Multiple Login Screens and Namespaces

I have a problem I can't figure out, in my application I have two login screens, one for the admin the other for the regular user. These login screens however point to the same controller in the same Auth namespace aside from that I have separated the rest of my controllers and routes into two namespaces; FrontEnd Namespace and BackEnd namespace.
Now my issue right now is when a regular user uses their credentials to login from the backend they are allowed access, I installed this package kodein/acl to handle roles and permissions and it seems to be working because when a user logs in to the backend now they can't do anything. The problem now is that even though they can't do anything they are still able to redirect to admin dashboard.
What I want here is this; when a regular user tries to login to admin backend they are denied access. I am a bit confused, i dunno how to o about it.
Do I have to create separate auth controllers and methods in both namespaces? Is that even possible? How would i go about it?
I use AngularJS for my frontend so in my route file i have this:
Route::group(['domain' => 'admin.website.loc'], function() {
Route::any('{url?}', function($url) {
return view('backend.index');
})->where(['url' => '[-a-zA-Z0-9/]+']);
});
Route::any('{url?}', function($url) {
return view('frontend.index');
})->where(['url' => '[-a-zA-Z0-9/]+']);
Which catch all urls and return to a single Index page,on the front end since i use JWT for authentication it validates the token on the frontend and if invalid or not available takes the user to the login page.
I thought of something else, maybe a temporary measure maybe permanent, i added the following code to my login function():
$url_parts = parse_url($request->url());
$host_parts = explode('.', $url_parts['host']);
if ($host_parts[0] == "admin")
{
$user = User::find(Auth::user()->id);
if (!$user->is('administrator'))
{
Auth::logout();
return response()->json(['error' => 'You Are Not Authorized!']);
}
}
first i get the request url,
then i get the "host" part of the request url and split it using '.' as the delimiter, this way i can check the subdomain.
Since my admin side uses a sub domain i check to see if the login request was from a url with the 'admin' subdomain, if it was then i check the authenticated user's role to see if they're administrator, if they are not, i log them out immediately and return an error message.
This way i don't have to create a separate function and route for the two login screens.

Integrating Laravel, Facebook and Angular with token-based-authentication

My use case:
User is already logged in automatically server side using Facebook with laravel and Socialite.
I check if the user exists in the db and if not create it and log them into laravel.
Then I need to start an Angular app and make sure they are logged in with Laravel / Facebook.
After reading this article, it looks like this token based approach is what I should take.
In the tutorial you serve a login form with Angular, and then pass the email and password to an authenticate controller (Laravel), which returns a token (create by JWT-Auth).
Once the token is in Angular all is well, my problem is that I want to get the token directly into Angular without a login form since the user is already logged in as mention above.
I'm wondering if I could just output the token in markup somewhere and then pick it up from Angular or would that somehow be a security risk? I guess people will only be able to view source and see their own token?
If this is the wrong way to do this, then how should I do it? Do I need to authenticate with Facebook with Javascript, and then create a new laravel user with ajax?
Thanks so much!
One approach you could take is to add something to your .config block that checks for the presence of a JWT in local storage and if there isn't one there, makes a request to the API to see if the user is logged in on the Laravel side. If the user is logged in, a JWT is returned which can be picked up and saved in local storage. Since the .config block is run when the Angular app loads, this will only happen once, which is probably what you're looking for.
Here's what that might look like. First the Laravel side:
// AuthenticateController.php
...
// Simulates a user being logged in on the Laravel side through something
// other than credentials sent from the front-end. Obviously you would use
// Socialite
public function authenticate()
{
$user = User::find(1);
$token = JWTAuth::fromUser(1);
return response()->json(compact('token'));
}
...
Then the Angular:
// app.js
...
.run(function($rootScope, $state, $auth) {
if(!$auth.isAuthenticated()) {
// No credentials provided because the user is already logged in on the server
$auth.login().then(function() {
$state.go('users');
}
}
$rootScope.$on('$stateChangeStart', function(event, toState) {
...
This would just run when the Angular app loads, which will be after your user has logged in with Socialite. It's essentially just checking whether there is a user logged in on the back end and if so, the token is retrieved. It's a bit hacky and the interface isn't obvious, so it might not be the best solution.
You would need to arrange your authenticate controller on the Laravel side such that it returns the token if the user has logged in via socialite or require credentials if he/she hasn't (which is the traditional login).
You could also look at this approach to see if it works for you: https://github.com/barooney/jot-bot/tree/socialite
Let me know if that works out!

Cakephp Auth component, Multiple User Role sessions in same browser

I am using Cakephp 2.0 and Auth Component. My website consists of 2 user roles as follows
1. Admin
2. User
At a Time in a Browser either Admin or User can login to the website using Auth Component. it's not possible to handle Both User roles can log into the website at the same time in same browser. Is there any way to do it CAKEPHP. Now My client wants to login as Admin and User in same browser. But in Joomla and other frameworks has this feature. extremely sorry for this basic question
Depends on how your roles are defined and how your admin section is built. If you done it with proper prefix routing (/admin/:controller/:action/) then it is easy.
In you AppController::isAuthorized() just add a check like
if ($this->Auth->user('is_admin') == 1 && $this->request->params['prefix'] == 'admin') {
return true;
}
If you have an array of rules use in_array() to check for the allowed roles.
For more details read this link.

How to determine if user has logged out on another page

I am running a Google App Engine project where everytime the user takes an action I want to check to see if the user is 1)logged in 2)an admin. This is the code I have for the appuser:
class AppUser
{
private UserService userService;
private User user;
public AppUser()
{
userService = UserServiceFactory.getUserService();
user = userService.getCurrentUser();
}
public IsAdministrator()
{
if(IsLoggedIn())
{
return userService.IsUserAdmin();
}
return false;
}
public IsLoggedIn()
{
return user == null;
}
}
When I log out with my app this works fine. However, if I log out on another page (like on google calendars or something) the app still thinks I'm logged in. Is there another better way to check if the user is still logged in?
Also I know that this can be done with security-constraint in the web.xml however that will not work in this case as I need to take certain actions if the user has logged off.
I am using App Engine SDK 1.7 and GWT SDK 2.4
Two ways to notify app about user logging out:
Synchronously - server actively notifies client (browser) about log-out. Use Channels API to send push notification to client. There is a GWT wrapper.
Asynchronously - server notifies client about log-out when client makes communication to server, i.e. in every RPC call add authentication check. If user id logged-out, raise an exception, which can be handled by GWT.
I ran into this today, though it was worse: I'd logged out as user A (from a Google Sites page), and logged in as user B, but my GAE app still thought I was logged in as user A. Argh.
The reason for this is that there are two cookies involved, one for tracking which Google user is logged into Google, and another for tracking which GAE application user is logged into my GAE application. Recall that a GAE could be using any federated authentication service, not just Google's. My application has no access to the google.com cookies, so I can't directly check whether user A is still logged in (or which user is currently logged in).
Unfortunately, I've not yet found a straight forward "federated logOUT" mechanism, though it is possible that Google Identity Toolkit can be used for detecting that the expected user is no longer logged in.
I found others discussing this issue:
How to manage multiple accounts login and logout in different browser pages?
UserService retrieves wrong user after logout
Update
I came up with a solution that works for my application, where I have a page that redirects the user, a student, to his or her classroom's home page. Since this is accessed infrequently by any one student (a few times a day), but which needs to know which student is logged in, I took the following approach which works for me:
User goes to page A, which clears the ACSID and SACSID cookies, and redirects to Google for the user to login.
User is probably already logged in, so Google (with several redirects) updates the ACSID and SACSID cookies to the currently logged in user, and redirects back to my application at page B.
Page B finally takes action on behalf of the logged in user, "confident" that the correct user is logged in (to the extent that pages are confident). ;-)
Here's a code sketch of the approach:
# My BaseHandler has a clear_cookie
class LoginAndRedirectHandler(base_handler.BaseHandler):
def get(self):
self.clear_cookie('ACSID')
self.clear_cookie('SACSID')
self.clear_cookie('dev_appserver_login')
if 'continue' in self.request.params and \
self.request.params['continue'].startswith('/'):
url = self.request.params['continue']
else:
# Whatever your page is that needs an up to date logged in user
url = users.create_login_url('/PageB')
if isinstance(url, unicode):
url = url.encode('utf8')
logging.info('Redirecting to ' + url)
self.redirect(url)
return
The reason I said infrequently above is that this process is expensive in time, with at least 4 or 5 redirects involved.

Resources