掲示板

Programmatically auto-login

thumbnail
9年前 に David Yari Podio Casares によって更新されました。

Programmatically auto-login

Junior Member 投稿: 36 参加年月日: 11/03/24 最新の投稿
Hi there,

I've developed an auto-login hook to allow users to log-in in Liferay using an encrypted token that only works for a limited amount of time. The hook is done and works wonderfully, so whenever someone calls to "/c/portal/login?socialToken=xxxxxxxxx", the token is decrypted and, if still valid, allows the user to login.

The problem I'm facing now is, I want to login into Liferay programmatically using the auto-login hook (with "programmatically" meaning without having to call to the "/c/portal/login/" URL).

For the moment, I've been trying to search in the Liferay code how it is done, but I can't find it.
Looking at the "/portal/login" strut action code, it basically redirects the petition to "/login/login" action, which is handled by the "com.liferay.portlet.login.action.LoginAction" class. In there, the "login" method is called.
As far as I can see, the method is basically getting the "login" and "password" parameter values and calling LoginUtil.login. Then I've seen the code of "LoginUtil.login" method and it doesn't seem to manage the auto-login attempts (in fact if you pass to it a request with the parameter "socialToken" setted and without the "login" and "password" parameters, it throws an Exception).

So, the question is, where's the code that manages the login requests that sould be managed by the auto-login hooks? Or, can someone explain what happens exactly when you do an auto-login, and how it could be replicated programatically?

Thank you!
thumbnail
9年前 に David H Nebinger によって更新されました。

RE: Programmatically auto-login (回答)

Liferay Legend 投稿: 14919 参加年月日: 06/09/02 最新の投稿
Auto login is handled by servlet filters. Check out com.liferay.portal.servlet.filters.autologin.AutoLoginFilter and the various SSO implementations in com.liferay.portal.servlet.filters.sso package.

What you've laid out so far is just the enhancements to the login process itself, but the servlet filter should complete your implementation.
thumbnail
9年前 に David Yari Podio Casares によって更新されました。

RE: Programmatically auto-login

Junior Member 投稿: 36 参加年月日: 11/03/24 最新の投稿
David H Nebinger:
Auto login is handled by servlet filters. Check out com.liferay.portal.servlet.filters.autologin.AutoLoginFilter and the various SSO implementations in com.liferay.portal.servlet.filters.sso package.

What you've laid out so far is just the enhancements to the login process itself, but the servlet filter should complete your implementation.


Thank you David, that was indeed the code I was looking for.

Cheers!
thumbnail
9年前 に David Yari Podio Casares によって更新されました。

RE: Programmatically auto-login

Junior Member 投稿: 36 参加年月日: 11/03/24 最新の投稿
By the way,

if someone needs the code to do a programmatic log-in in Liferay, here's a very simple way to do it:


	public static void login(User user, HttpServletRequest request) throws Exception {
		String username = String.valueOf(user.getUserId());
		String password = user.getPassword();
		boolean encPassword = user.isPasswordEncrypted();
		HttpSession session = request.getSession();
		session.setAttribute("j_username", username);
		if (encPassword) {session.setAttribute("j_password", password);}
		else {throw new Exception("Password encryption not implemented");}
		session.setAttribute("j_remoteuser", username);
	}


In my portal I'm not going to use unencrypted passwords, that's why it throws an Exception if password is not encrypted (I had no time to dedicate to this possibility). If your portal uses the "use unencrypted passwords" config option you should develop that part too.

Cheers!
6年前 に Traolly Xiong によって更新されました。

RE: Programmatically auto-login

Regular Member 投稿: 195 参加年月日: 11/12/30 最新の投稿
Hello all,
Currently when hitting certain secured URLs, I have a auto login hook class that is enabled to trigger. Certain
secured URLs like "/api/jsonws/*" do not trigger the auto login hook class. So what I did was I created servlet filter class
that I can intercept those types of secured URLs and I want to trigger the auto login hook class programmatically. Is that possible?

ex) hook "portal.properties" file
auto.login.hooks=com.qad.portal.security.auth.QADAutoLogin

ex) hook "login-hook.xml" I specify the pattern and filter class.

<servlet-filter>
<servlet-filter-name>RemoteJsonWebServiceFilter</servlet-filter-name>
<servlet-filter-impl>com.qad.portal.security.auth.QADRemoteWSAutoLogin</servlet-filter-impl>
</servlet-filter>

<servlet-filter-mapping>
<servlet-filter-name>RemoteJsonWebServiceFilter</servlet-filter-name>
<before-filter>Virtual Host Filter</before-filter>
<url-pattern>/api/jsonws/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</servlet-filter-mapping>

Let me know if you have good tips on how I can achieve this.

Thanks.
thumbnail
6年前 に David H Nebinger によって更新されました。

RE: Programmatically auto-login

Liferay Legend 投稿: 14919 参加年月日: 06/09/02 最新の投稿
You don't need a servlet filter.

/api/jsonws uses the AuthVerifier chain which currently only has the BasicAuthHeaderAuthVerifier and the PortalSessionAuthVerifier (that's the one that looks at the p_auth token value) that apply.

To add your own authenticator, just implement the AuthVerifier and, in your @Component properties, ensure that the /api/jsonws is part of the url pattern.









Come meet me at 2017 LSNA!
6年前 に Traolly Xiong によって更新されました。

RE: Programmatically auto-login

Regular Member 投稿: 195 参加年月日: 11/12/30 最新の投稿
Hello David,
You may need to excuse my ignorance. If below is what I have:

1) "portal.properties" referenced from "login-hook.xml"

auto.login.hooks=com.qad.portal.security.auth.QADAutoLogin

2) class
public class QADAutoLogin extends BaseAutoLogin {

@Override
protected String[] doLogin(HttpServletRequest request, HttpServletResponse response) throws Exception {
.............
return credentials;
}

With what you said ..

"To add your own authenticator, just implement the AuthVerifier and, in your @Component properties, ensure that the /api/jsonws is part of the url pattern."

Can you help elaborate a bit more on details on how I can trigger the override auto login class function when making secured json web service URLs?

Any more clarity is very much appreciated.

Thanks.
thumbnail
6年前 に David H Nebinger によって更新されました。

RE: Programmatically auto-login

Liferay Legend 投稿: 14919 参加年月日: 06/09/02 最新の投稿
Although they are related in that they handle authentication, they are a little different.

AutoLogin covers aspects like CAS, SiteMinder, etc., but they are in response to handling an actual login event. Because it is invoked during login handling, the pre- and post-login events will execute and the outcome could be a login failure or even a redirect after login. It is really meant to be invoked in the process of handling browser requests when a real human is driving the incoming requests.

The AuthVerifier is different in that they are used in conjunction with an incoming request, typically some sort of web service request, where the user must be authenticated in order to invoke the service, but the other aspects of the AutoLogin (pre- and post-login hooks, redirect after login, redirect to failure with auth failure reasons, etc.) are not involved.

It is basically "Is this a good user? No, return the 401 not authorized. Yes, invoke the web service".

Liferay normally invokes the BasicAuthHeaderAuthVerifier (handles the basic auth header) or the PortalSessionAuthVerifier (compares the p_auth value to the value in the session of the currently logged in user, primarily used by the Liferay JS to invoke jsonws services during a logged in session).

As I said, the AutoLogin and AuthVerifier are pretty similar, so much so that most of the AuthVerifiers I've looked at extend their AutoLogin counterparts and implement the AuthVerifier interface. But while AutoLogin is the general case invoked during normal authentication process, the AuthVerifier is the one used for the /api/jsonws process.

I didn't realize you were talking about 6.x; for 6.x there is a different process for adding in the AuthVerifier implementation and adding it to the auth verifier chain. Check out the verifier section in portal.properties to see what is involved for integrating into the AuthVerifier chain: https://github.com/liferay/liferay-portal/blob/6.2.x/portal-impl/src/portal.properties#L3867-L3900









Come meet me at 2017 LSNA!
6年前 に Traolly Xiong によって更新されました。

RE: Programmatically auto-login

Regular Member 投稿: 195 参加年月日: 11/12/30 最新の投稿
Thanks David. I'll look into it and see what I can come up with.

On another note, can you confirm if the option of writing a servlet filter class to log in a user manually is still an option that might work?

ex)
- "liferay-hook.xml"

<servlet-filter>
<servlet-filter-name>RemoteJsonWebServiceFilter</servlet-filter-name>
<servlet-filter-impl>com.qad.portal.security.auth.QADRemoteWSAutoLogin</servlet-filter-impl>
</servlet-filter>

<servlet-filter-mapping>
<servlet-filter-name>RemoteJsonWebServiceFilter</servlet-filter-name>
<before-filter>Virtual Host Filter</before-filter>
<url-pattern>/api/jsonws/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</servlet-filter-mapping>

- In the hook override class "processFilter()" override method:
...................
User user = autoLogin.getUserFromSSOCookie(request, response, companyId);
if(user != null) {
_log.warn("user Id: "+user.getUserId());
String jUsername = String.valueOf(user.getUserId());
String jPassword = user.getPassword();
boolean encPassword = user.isPasswordEncrypted();
HttpSession session = request.getSession();
session.setAttribute("j_username", jUsername);
if (encPassword) {
session.setAttribute("j_password", jPassword);
} else {
/*session.setAttribute("j_password", PasswordEncryptorUtil.encrypt(jPassword, user.getPassword()));
if (PropsValues.SESSION_STORE_PASSWORD) {
session.setAttribute(WebKeys.USER_PASSWORD, jPassword);
}*/
_log.warn("Password encryption not implemented");
}
session.setAttribute("j_remoteuser", jUsername);
}
................

I would think there might be an option of doing it at the servlet filter layer.

Thank you sir.
thumbnail
6年前 に David H Nebinger によって更新されました。

RE: Programmatically auto-login

Liferay Legend 投稿: 14919 参加年月日: 06/09/02 最新の投稿
Traolly Xiong:
On another note, can you confirm if the option of writing a servlet filter class to log in a user manually is still an option that might work?


You know, I'm not really sure.

My gut seems to believe the answer is no. I mean, there are a normal set of security filters and others that will be invoked on the way into the actual servlet call. I don't know what the servlet filters look at to determine if authentication was already completed, but you'd have to ensure that your filter came in front of any Liferay security filter plus you'd have to have some sort of indicator in place before the security filter is called so it assumes authentication is already completed and not use one of the Liferay methods.

Ultimately of course this is why it is usually better to do things "the Liferay way". If you build as an AuthVerifier implementation and make sure it is in the chain, you'll get invoked for auth purposes and you know that if you pass the authentication the rest of Liferay will do the right thing.

If you try to go it alone, you may find that you're needing to build out a lot of unnecessary "hacks" in order to get it to work.









Come meet me at 2017 LSNA!
6年前 に Traolly Xiong によって更新されました。

RE: Programmatically auto-login

Regular Member 投稿: 195 参加年月日: 11/12/30 最新の投稿
Quick update David. I was able to use the servlet filter to programmtically log in the user and get a Liferay logged in cookie.
The code is a bit similar to what I've put into this thread.

So each time a "/api/jsonws/*" a request comes in, the servlet filter picks up on that, and if the user is NOT logged in and contains a custom encrypted cookie, I've programmed the filter class to programmitically get the user object and log in that user (update request sessions attribute variables). If the request doesn't fall into that logic, then it just continues to do it's normal path and returns a 403 authentication error.

Hope this helps others.

Thanks for you help and tips as usual.

TRX