Multiple Login Screens and Namespaces - angularjs

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.

Related

Blank page after login using bookmarked authorization URL in IdentityServer4

We have discovered that our users very often for the first time visits our web application by browsing the direct URL of the OIDC client (https://oidcclienturl.com/), The ASP.NET Core OIDC authentication middleware kicks in and the user gets redirected back to Identityserver 4 login page.
Everything works fine but then they decide to add the (temporary? state, nonce, cookies...) authorization URL as a bookmark in their browser before entering their credentials and continuing back to the web application.
This causes an issue when the user later uses the bookmark in a new session. The login seem to actually work after entering valid user credentials even if the user uses an old authorization URL, but when the user gets redirected back to the web application they end up on a blank page (https://oidcclienturl.com/signin-oidc).
After the blank page have been loaded the user is able to browse the direct URL (https://oidcclienturl.com/) sucessfully and appear as an authentcated user in the web application.
Any ideas whats causing the blank page?
That blank page shouldnt exist, if I understand it correctly its the default callback path of the oidc authentication middleware in ASP.NET Core.
Unfortunately, the real-world problem of users bookmarking the login page isn't handled cleanly by OIDC, which requires the client app to initiate the login flow.
I've addressed this by adding a RegistrationClientId column to my user data table, which is the Identity Server ClientId corresponding to the client app that called IDS when the user account was created. In the client app configuration, we use the custom Properties dictionary to add a URI fragment:
new Client
{
ClientId = "some_client",
ClientName = "Some Client",
ClientUri = "https://localhost:5000",
Properties = new Dictionary<string, string>
{
{ "StartLoginFragment", "/Auth/StartLogin" }
}
// other config omitted
};
When a user logs in, an empty return URL indicates IDS wasn't called by a client app, so we use RegistrationClientId to query IClientStore, then we combine the ClientUri and StartLoginFragment URIs and use the resulting URI to redirect the user back to the client application.
Over in the client application, that endpoint kicks off the OIDC sign-in flow, and since the user is already signed-in on IDS, it comes right back to the correct location in the client app. The controller action looks like this:
[HttpGet]
public async Task StartLogin()
{
await acctsvc.SignOutAsync();
await HttpContext.ChallengeAsync("oidc",
new AuthenticationProperties()
{
RedirectUri = "/"
});
}
The call to SignOutAsync just ensures any client-app signin cookies are cleaned up. It's in our custom account service, but it just runs HttpContext.SignOutAsync on the usual "Cookies" and "oidc" schemes. Normally that would also result in a signout call to IDS, but the redirection by the subsequent ChallengeAsync replaces the pending signout call.
The downside is that the action is an HTTP GET meaning pretty much anyone could theoretically trigger this action. At most it would be an annoyance.
In the special case where your IDS is only handling auth for a single client, you can skip a lot of that -- if they land on the page with no return URL, just send them to your client app start-login endpoint straightaway, before they login.

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!

Unable to read sessions in cake php

I have created a login functionality and everything is working fine. The only problem is that I am able to access the session in the users controller and views in user.
When I tried to access the user session in another controller, it shows me undefined.
Below is my login function code.
if ($this->Auth->login()) {
$user_data = $this->Auth->user();
$this->loadmodel('GeneralUser');
$result = $this->GeneralUser->find('first',array('conditions' => array('user_id' => $user_data['id'])));
$user_data_complete = array_merge($user_data,$result['GeneralUser']);
$this->Session->write('user',$user_data_complete);
$this->redirect('/dashboard/dashboard/');
$this->Session->setFlash('You are successfully logged in');
return $this->redirect($this->Auth->redirectUrl());
}
The user is successfully logged in and redirected to dashboard controller where I am unable to access the sessions of then Auth user. If I go back to users/myaccount, I am able to access the session.
Strange, why am I not allowed to access the user sessions in other controllers?
You SHOULD NOT use session_start() or any GLOBALS, if you do then there is no point in using a PHP Framework. Always stick to the conventions and avoid spaghetti code.
If you want to read a Session value in a Controller then use the Session Component, if you want to read the value of a session in a view then use the Session Helper.
Reading the documentation is my best advice: http://book.cakephp.org/2.0/en/development/sessions.html
It got fixed..I was using the normal php session_start() in the top of the controller which was causing the issue.

CakePHP 2 and Croogo with Basic Authentication for REST

When trying to login via REST, I simply added:
if ($this->RequestHandler->isXML()) {
$this->Auth->authenticate = array('Basic');
}
To my plugins AppController. When i request via a rest client i get:
DbAcl::check() - Failed ARO/ACO node lookup in permissions check.
With my user object dumped. Strange, it seems like it's logging me in but not reading permissions correctly?
When i added:
$this->Auth->authorize = array('Controller');
and implemented the isAuthorized method:
public function isAuthorized($user) {
if (isset($user['role_id']) && $user['role_id'] == 1) {
return true; //Admin can access every action
}
return false; // The rest don't
}
It worked.
There is one fundamental thing here that you seem to be missing: Authentication and Authorization are two different things.
Authentication is the process of identifying users by provided credentials and ensuring that users are who they say they are. This is generally done using an username and password.
Authorization is the process of ensuring that the current user is allowed to access a
specific resource.
The error you were getting is an Authorization error and from it I call tell that you're trying to use ACL. Your fix to the issue is to configure Controller based Authorization andthrough it allow the admin to access everything. Controller Based Authorization is not related to ACL authorization. Check the links provided.
The AuthComponent implements 3 different types of Authentication:
FormAuthenticate - allows you to authenticate users based on form POST
data. Usually this is a login form that users enter information into.
BasicAuthenticate - allows you to authenticate users using Basic HTTP
authentication.
DigestAuthenticate - allows you to authenticate users using Digest
HTTP authentication.
If you're developing a REST service I'd recommend using Digest Authentication as the "best to have" but it'd still depend on what you're logging in.

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

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.

Resources