Cakephp2 : Using multiple authentication manager - cakephp

I took back the maintenance of a cakephp app, however I have never been a cake developer and I just encountered my first problem.
Currently users are logging in by using a simple form, it is something really simple and it looks like this:
$this->Auth->authenticate = array('Form' => array('userModel'=> .....
Whenever I try to access a protected page, I am getting redirected to the page which implements this login form, this is totally fine and I don't have any problem with that.
However, I have different clients that requires different "authentication format" (if I may say), some wants an Ldap authentication, others an openId authentication, others a CAS authentication...
I managed to create a working authentication for every "system" by extending the BaseAuthenticate and implementing my logic to connect to the app.
Let's take the example with OpenId (which is a little explained in the cakephp book and that I base myself on : http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html). I have created my OpenIdAuthenticate in app/controller/component/auth, implemented the method,...
As in the book, I have chosen the openId as the "main authentication" is my appController :
$this->Auth->authenticate = array(
AuthComponent::ALL => array('userModel' => 'Member'),
'OpenId',
'Form'
);
For the CAS I have the same with Cas instead of OpenId and whenever i try to access a protected page I am redirect to my cas server, where I log myself and I am logged in the cake application (so no problem).
I have also created another method in my user controller in case of the external authentication is broken (if we have any problem, it will probably be useful still to be able to log ourselves for maintenance).
To do so I created an adminLogin method (+ the ctp view file) where I "forced" the original Form authentication by doing as it was written before:
public function adminLogin() {
$this->Auth->authenticate = array('Form' => array('userModel'=> .....
if ($this->request->is('post')) {
//rest of the logic
}
}
Whenever I query the uri /users/adminLogin, I am using the classic authentication system and have access to all the protected pages by bypassing the external authentication.
First question: Is it recommended to do something like that? The only goal is to have access to the content of the app as long as our database is up (in case of).
Now comes the part I still haven't found the solution. As I said, I have different clients with different needs and I don't want to have the classic version hosted for client X, the OpenId for the Y and the Ldap for the Z. I would like the same application everywhere and it will be up to the client to use whichever system he wants to use.
This means, I want to be able to change the authentication method dynamically. What i would like to do is to create a page (only available for the administrator obviously) where it will be able to choose between all the supported system and to configure the system.
For example, I choose Ldap, I will have to give the ip,port,reading suer and pwd, DN, filter,etc.... If I choose cas, the url,port,...(you understood).
And when I press the submit button, my authentication system has changed (except for the adminLogin page).
This is where I would like you to help me find a way to do so. I tried to create a global variable when I click on submit using
Configure::write('SystemUsed','LDAP');
And in my appController in the beforeFilter(), I tried to do :
if (Configure::read('SystemUsed') == 'LDAP') {
$this->Auth->authenticate(...);
else if (Configure::read('SystemUsed') == 'OpenId') {
$this->Auth->authenticate(...);
}
etc. But it is not working, the variable is becoming null after the submit and it doesn't look like a clean way to do it.
Can anyone help me, please?

Related

Accessing user details using Active Directory in an ASP.NET Core MVC app with Windows authentication

I was trying to access user information like first name, last name of the user in my ASP.NET Core MVC project with Windows authentication. I actually make it work after searching for a solution on the web but I am quite new to this stuff and beginner level programmer so not understanding what is happening in the part that I just copy paste in my project.
I couldn't find any explanation in that website as well. I would be really happy if someone can explain this to me. Many thanks in advance.
The website reference for this code: https://sensibledev.com/how-to-get-user-details-from-active-directory/
Home controller:
var username = User.Identity.Name;
using (var context = new PrincipalContext(ContextType.Domain, "yourdomain"))
{
var user = UserPrincipal.FindByIdentity(context, username);
if (user != null)
{
ViewData["UserName"] = user.Name;
ViewData["EmailAddress"] = user.EmailAddress;
ViewData["FullName"] = user.DisplayName;
ViewData["GivenName"] = user.GivenName;
}
}
That code takes the username of the user who logged into your website and looks it up on your domain to find more information about the person.
var username = User.Identity.Name;
The User property is ControllerBase.User, which refers to the user currently logged into your website. Since you're using Windows Authentication, this will refer to an Active Directory user. User.Identity.Name gets just the username.
The rest is for looking up the account in Active Directory.
new PrincipalContext(ContextType.Domain, "yourdomain")
This means "I want to talk to a domain called yourdomain".
UserPrincipal.FindByIdentity(context, username)
UserPrincipal.FindByIdentity finds an account on the domain. So this is saying "find this username on the domain".
Then the users details from the account are put into the ViewData collection so that the data is accessible in the view. More details on that here.
From your website's perspective, all Windows code runs under some Windows account.
If you use IIS and Forms authentication for example, then Windows knows nothing about you - you are likely to be running under an anonymous account name which all users will run under. If you drill down through your running code, it is possible to find different Windows accounts at different code levels, such as in your top level code, the underlying IIS thread, etc.
You are trying to use Windows accounts for your web site but you have to ensure that the web server it is running on is also using Windows Authentication - I know you checked this option when creating your site.
Your user identity can be cast to various types because it has to work seamlessly whichever authentication methodology is in use. You can also check your user to see if it is of a particular security regime.
Have a look at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
You get the security principle information using
var context = new PrincipalContext(ContextType.Domain, "yourdomain")
PrincipleContext is the class that has the information once you create a new instance of it, passing in parameters for the type of domain (an enumeration) and the name of your domain (a string).
The USING block ensures that the instance is disposed once the block completes - otherwise you have to call DISPOSE on that instance yourself (remember if there is an exception you might not have captured this so you will at least have to manage this scenario.
Once you have an instance of of your domain context you can use it to search (in the case of Windows, the LDAP database) for users, whether by SID or unique name, in your case (every name must be unique - two users in the domain cannot have the same name).
The website has the security ID of the user, the code you are following gets a Domain object for that user which has the properties you will display. You could call other objects that might tell you which Windows Security Groups the user is a member off. In that way you can have a web site where a users ability to view a web page or click a button is down to which Groups in the Domain the user is a member of.

IdentityServer4: allow login only for specific user/client combinations

I want to use IdentityServer4 as a common login for my own web applications.
Not all users are free to use all apps and obviously I could make all apps have users be rejected that aren't allowed to access them.
It seems a little more elegant to have a common "this app isn't activated for you" page centralized in the identity server though. That way, I need to implement that page only once. The identity server would have to have knowledge about which user may access which client, but that's reasonable in my scenario: they are all my own apps anyway.
I'm not sure what the right place is to hook the test in. It can't be the login page as the user may already be logged in to the identity server from a client he does have access to.
I wouldn't go for this approach, but I do not know the design of your apps.
I think that the url may confuse the user. Since it is the url of the IdentityServer where they see the "this app isn't activated for you" message. What does that mean to the user and where to go from there?
Besides, IdentityServer is meant to authenticate users, not to authorize users. So it doesn't seem right to move this kind of logic to IdentityServer. It also sounds like extra work.
Keep it simple. Keep authorization close to the resource and create one page with the message. Copy that to all your apps and css does the rest.
And use the default behaviour. In case an anonymous user hits a secured method, the user will automatically be rerouted to the login page. In case an authenticated user hits a method where it doesn't have access, it reroutes to the default (apps) Account/Denied page.
You can override the path in you startup configuration:
.AddCookie("Cookies", options =>
{
options.AccessDeniedPath = "/accountdenied";
})
You can show the "this app isn't activated for you" page, or you can go from there and redirect with code to the IdentityServer page. With the possibility to add additional information to customize the page.
Perhaps you can enter the page of IdentityServer instead, if that fits your design better. I haven't tried it, so I do not know if that's possible.
But in any case I would keep the authorization logic in the app.

issue in CakePHP authentication

I am using two cakephp framework . Problem is when I logged in to 1 st one, without login I can login to 2nd one by using same session.
how to resolve this issue . I am using cakephp 2x
From what you are saying I understood that you have two applications running on the same server (the default realm for Auth plugin). And what is happening is that once you login in one application the other lets you access the protected locations without the need to login (I've faced this).
IF this is your issue you can either change the prefixes of the applications in the configuration file app/Config/core.php.
It is one line like this:
<?php [...]
$prefix = 'myapp_';
Change the prefix to other name.
OR
Configure the realm key in the AuthComponent configuration to other value than the 'servername' which is the default.
For this one check the docs and search for 'realm'.

Single Page Application login with Spring and AngularJS

I'am creating application which can be used by unknown and logged in users. Only difference is that logged in user can use some additional functions like saving its content in database.
All communication is based on ajax calls, so what I need is to deny access to some controller functions (end points) in backend for unknown users and on the client side I need to know that it is in logged in state to set this extra functions active. Only one page, login form should be in dialog. I'm little bit confused, because standard Spring Security aproach doesn't fit this case. I was reading this tutorial but I cant't fully understand it.
First: What Principal object does? They send credentials to this endpoint on submit with login() function but where is handled password check? What if I have my users in database?
Second Is it possible to write this configuration in XML style? I guess that it can be done with <intercept-url/> in spring-security.xml file.
Principal Object
The Principal Object is used to be able to get basic information about a user that is attempting to login when using automatic server authentication (i.e. LDAP). However, you will only be able to get a username from the principal object. With a server JBoss/WildFly, for example, you can link the server to Active Directory to allow Microsoft Windows to authenticate users.
Simple Solution
First, Spring Security will add additional complexity to your application where it doesn't sound like you are trying to do that. Instead, use a simple Servlet Filter. If you are using LDAP on a JBoss/WildFly sever, you can make a POST to j_security_check and the server will send the request to the filter if correct credentials are provided. Inside the filter, you may use the getName() function of the Principal object to get the username so that you may store it in the user's session. However, if you are not using LDAP, you may make a simple POST to a Java Servlet or Spring Controller (with an #RequestMapping) to attempt to login the user and store the user's information in the session.
At this point, you can filter out what URLs you will allow users to see. For example, the URL that contains /administrator/some/other/stuff.jsp could be restricted if the URL contains the word "administrator" in the first directory of the URL.

Cakephp - Using auth with a 3rd party provider

I'm in the process of creating a XML-RPC that interacts with Vbulletin from Cakephp. I currently have the functionality to hit the end point, log a user in, and retrieve the data set, as well as the cookies, etc.
Now, the calls come from Cakephp, I have a users table, which I only store, the usersname from vbulletin, the vbulletin users ID, and their avatar. I'd like to implement some type of auth. I'm not entirely sure if this is possible or not. The only reason I have a users table is to store a minimal set of information. When the user logs in on the Cakephp side, it's actually sending a xml-rpc client call to the vbulletin api, and logging the user in using the api.
So, with all of this known, is it possible to restrict access to various views, etc within cake? I'd like to use some of the basic auth components, such as:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
I'm guessing, if this is not possible, I'll have to manually write the session cookies received from Vbulletin in Cake, but how would I restrict access to the various views and methods within the controllers in doing so?
Update: I ended up using the below to accomplish this.
Since I am storing the vbulletin users id in the users table, I was able to:
$user = $this->User->findByVbulletinid($userid);
$user = $user['User'];
$this->Auth->login($user);
Link to Cakephp manual login not initiating session
Update1: We'll, I thought this was working, until I removed the Debug Kit. Now, after I login, I'm automatically logged out, Really odd.
If I want to call $this->Auth->login($loginData), shouldn't I be able to supply $loginData, which in my case, would look like this:
Array
(
[User] => Array
(
[username] => testuser
[password] => hashedpasswordhere
)
)
Basically, the login method in the Users controller, I cannot simply call $this->Auth->login() because I need to first, take the credentials from the form, and log the user in via the API for vbulletin.
Any thoughts here?
You will have to implement a custom Authentication Handler that is connected to the "Vbulletin". Then when you log a user in $this->Auth->allow('add'); should work just fine.
Also consider additional means of logging a user in. what will happen if that external service is down? Your users will not be able to log in at all?

Resources