authentication in liferay without login hook - authentication

I have a problem, I get the user and password of a view and I check if this data is correct in the data of liferay, when it's correct my method return 1 if the validation is true, but I don't know how to make the successful login in liferay, this is my method:
try {
long companyId = PortalUtil.getDefaultCompanyId();
System.out.println(companyId + " id company");
User user1;
try {
user1 = UserLocalServiceUtil.getUserByEmailAddress(companyId, name);
long cmp = user1.getCompanyId();
Company company = CompanyLocalServiceUtil.getCompany(cmp);
int a = UserLocalServiceUtil.authenticateByUserId(company.getCompanyId(), user.getId(), pass, null,
null, null);
if (a == 1) {
System.out.println("Log in successful");
}
} catch (PortalException e) {
e.printStackTrace();
} catch (SystemException e) {
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("algo salio mal");
}

This seems to be a case where you would need an auto-login hook. In Liferay 7, you just need components like in: https://www.e-systems.tech/blog/-/blogs/autologin-in-liferay-7
You can use an indicator within the user session, like a token, and check it in a custom logic:
#Override
protected String[] doLogin(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
final long companyId = portal.getCompanyId(request);
final HttpSession session = request.getSession();
// code your logic here..
final String[] credentials = new String[3];
credentials[0] = String.valueOf(user.getUserId());
credentials[1] = user.getPassword();
credentials[2] = Boolean.FALSE.toString();
return credentials;
}
This solution is also valid for LR6, the difference is that you are not using OSGi there, so you have to create a hook through the SDK.

Related

org.apache.geode.cache.UnsupportedOperationInTransactionException

Getting below exception while updating entry in the cache while establishing Many to Many relation.
org.apache.geode.cache.UnsupportedOperationInTransactionException: Expected size of 1 {[/__PR/_B__User_101]} for target=192.168.1.2(cacheServer2:7756)<v1>:41001 during a distributed transaction but got 2 {[[], [DistTxThinEntryState: ,regionVersion=2 ,tailKey=440 ,memberID=null]]}
at org.apache.geode.internal.cache.DistTXStateProxyImplOnCoordinator.populateEntryEventMap(DistTXStateProxyImplOnCoordinator.java:576)
at org.apache.geode.internal.cache.DistTXStateProxyImplOnCoordinator.doPrecommit(DistTXStateProxyImplOnCoordinator.java:484)
at org.apache.geode.internal.cache.DistTXStateProxyImplOnCoordinator.commit(DistTXStateProxyImplOnCoordinator.java:88)
at org.apache.geode.internal.cache.TXManagerImpl.commit(TXManagerImpl.java:426)
at com.trendcore.cache.peertopeer.service.UserServiceImpl.attachRoleToUser(UserServiceImpl.java:108)
at com.trendcore.cache.peertopeer.CacheApplication.attachRoleToUser(CacheApplication.java:121)
Cache Configuration -> It's Peer to Peer configration with 2 regions.
Properties properties = new Properties();
properties.setProperty("locators", "localhost[13489]");
properties.setProperty("mcast-address", "224.0.0.0");
properties.setProperty("mcast-port", "0");
properties.setProperty(NAME, "cacheServer1");
CacheFactory cacheFactory = new CacheFactory(this.cacheConfiguration);
cache = cacheFactory.create();
User Region
RegionFactory<Long, User> regionFactory = this.cache.createRegionFactory(RegionShortcut.PARTITION);
userRegion = regionFactory.create(USER_REGION);
Role Region
RegionFactory<Long, Role> regionFactory = this.cache.createRegionFactory(RegionShortcut.PARTITION);
roleRegion = regionFactory.create(ROLE_REGION);
User model resides in User region
public class User implements Serializable{
private Long id;
private String username;
private Map<Long,Object> roles;
//Getters , Setters
public void addRole(Long roleId) {
roles.put(roleId,null);
}
}
Role model resides in Role region
public class Role implements Serializable {
private Long id;
private String roleName;
//getters , setters
}
Users and roles are inserted in the respective regions using below code.
public void insertUser(User user) {
CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
try {
cacheTransactionManager.begin();
userRegion.put(user.getId(), user);
cacheTransactionManager.commit();
} catch (Exception e) {
cacheTransactionManager.rollback();
}
}
public void insertRole(Role role) {
CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
try {
cacheTransactionManager.begin();
roleRegion.put(role.getId(), role);
cacheTransactionManager.commit();
} catch (Exception e) {
cacheTransactionManager.rollback();
}
}
When any roleIds are put in existing cache user object then above exception is thrown.
public void attachRoleToUser(Long userId, Long roleId) {
Region<Long, User> userRegion = cache.getRegion(USER_REGION);
Region<Long, Role> roleRegion = cache.getRegion("Role");
CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
try {
cacheTransactionManager.setDistributed(true);
cacheTransactionManager.begin();
Role role = roleRegion.get(roleId);
if (role != null) {
User user = userRegion.get(userId);
user.addRole(role.getId());
userRegion.put(userId,user);
}
cacheTransactionManager.commit();
} catch (Exception e) {
try {
cacheTransactionManager.rollback();
}catch (Exception rbe){
}
throw new RuntimeException(e);
}
}
Any guidance in this case will be appreciated.
1.) Distributed transactions only work for Replicated Regions at this point.
2.) In the second case, only one region is now in the transaction boundary, so co-location is not needed.
3.) I think in your first case, you had two partitioned regions as part of a transaction, this requires the regions to be co-located ( the relevant data has to exist on the node, so it's also possible that one is a replicated region and the other is a partitioned)
Changed, attach user to role method to below and there is no exception.
Region<Long, User> userRegion = cache.getRegion(USER_REGION);
Region<Long, Role> roleRegion = cache.getRegion("Role");
CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
try {
//This is change fetching role information outside transaction boundry.
Role role = roleRegion.get(roleId);
cacheTransactionManager.setDistributed(true);
cacheTransactionManager.begin();
//This line is causing below exception
//org.apache.geode.cache.UnsupportedOperationInTransactionException: Expected size of 1 {[/__PR/_B__User_101]}
//Role role = roleRegion.get(roleId);
if (role != null) {
User user = userRegion.get(userId);
user.addRole(role.getId());
userRegion.put(userId,user);
}
cacheTransactionManager.commit();
} catch (Exception e) {
try {
if(cacheTransactionManager != null && cacheTransactionManager.exists())
cacheTransactionManager.rollback();
}catch (Exception rbe){
}
throw new RuntimeException(e);
}
And there is no exception.
However need more information on below points.
Transaction was set to distributed.
User and Role both regions were involved in this case transaction failed, with exception UnsupportedOperationInTransactionException
Distributed transactions are not working on multiple regions.

Basic Auth to Receive Token in Spring Security

I am implementing a RESTful API where the user must authenticate. I want the user to POST their credentials in order to receive a JSON web token (JWT), which is then used for the remainder of the session. I have not found any good sources of information to set this up. In particular, I'm having trouble with the filter. Does anybody have any information or tutorials to help me set this up?
The people at Stormpath have quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
By the way, you can also completely delegate the login/register/logout functionality to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/**
* Authenticates via username (or email) and password and returns a new access token using the Account's ApiKey
*/
public String getAccessToken(String usernameOrEmail, String password) {
ApiKey apiKey = null;
try {
AuthenticationRequest request = new UsernamePasswordRequest(usernameOrEmail, password);
AuthenticationResult result = application.authenticateAccount(request);
Account account = result.getAccount();
ApiKeyList apiKeys = account.getApiKeys();
for (ApiKey ak : apiKeys) {
apiKey = ak;
break;
}
if (apiKey == null) {
//this account does not yet have an apiKey
apiKey = account.createApiKey();
}
} catch (ResourceException exception) {
System.out.println("Authentication Error: " + exception.getMessage());
throw exception;
}
return getAccessToken(apiKey);
}
private String getAccessToken(ApiKey apiKey) {
HttpRequest request = createOauthAuthenticationRequest(apiKey);
AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
return accessTokenResult.getTokenResponse().getAccessToken();
}
private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
try {
String credentials = apiKey.getId() + ":" + apiKey.getSecret();
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});
Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
parameters.put("grant_type", new String[]{"client_credentials"});
HttpRequest request = HttpRequests.method(HttpMethod.POST)
.headers(headers)
.parameters(parameters)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Then, for every authenticated request, your backend will do:
/** This is your protected API */
public void sayHello(String accessToken) throws OauthAuthenticationException {
try {
if (verify(accessToken)) {
doStartEngines(); //Here you will actually call your internal doStartEngines() operation
}
} catch (OauthAuthenticationException e) {
System.out.print("[Server-side] Engines not started. accessToken could not be verified: " + e.getMessage());
throw e;
}
}
private boolean verify(String accessToken) throws OauthAuthenticationException {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
System.out.println(result.getAccount().getEmail() + " was successfully verified");
return true;
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.
Please take a look here for more information.
Hope that helps!
Disclaimer, I am an active Stormpath contributor.
Here's a working sample code from Spring Security OAuth github.
https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/jwt
You probably don't even need to mess with the filters as shown in the above example. If you've custom needs, please post some sample code.

Error when processing the authentication request in WSO2 Identity Server - NullPointerException

I'm having a trouble when authenticating with the WSO2 Identity Server.
I have a web page named avis.com, when I enter the page, click the login button, then the web page navigates to the login form of WSO2 Identity Server. But, when I enter use name and password into the form and click login. A error page appears as:
SAML 2.0 based Single Sign-On
Error when processing the authentication request!
Please try login again.
At the Apache Tomcat Log, errors appear:
Nov 07, 2013 3:12:32 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [SAML2ConsumerServlet] in context with path [/travelocity.com] threw exception
java.lang.NullPointerException
at com.travelocity.saml.sso.SamlConsumerManager.getResult(SamlConsumerManager.java:272)
at com.travelocity.saml.sso.SamlConsumerManager.processResponseMessage(SamlConsumerManager.java:246)
at com.travelocity.saml.sso.SAML2ConsumerServlet.doPost(SAML2ConsumerServlet.java:73)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
At the com.avis.saml.sso.SamlConsumerManager.getResult(SamlConsumerManager.java:272):
private Map<String, String> getResult(XMLObject responseXmlObj) {
if (responseXmlObj.getDOM().getNodeName().equals("saml2p:LogoutResponse")) //line 722{
return null;
}
Response response = (Response) responseXmlObj;
Assertion assertion = response.getAssertions().get(0);
Map<String, String> resutls = new HashMap<String, String>(); // line 72
/*
* If the request has failed, the IDP shouldn't send an assertion.
* SSO profile spec 4.1.4.2 <Response> Usage
*/
if (assertion != null) {
String subject = assertion.getSubject().getNameID().getValue();
resutls.put("Subject", subject); // get the subject
List<AttributeStatement> attributeStatementList = assertion.getAttributeStatements();
if (attributeStatementList != null) {
// we have received attributes of user
Iterator<AttributeStatement> attribStatIter = attributeStatementList.iterator();
while (attribStatIter.hasNext()) {
AttributeStatement statment = attribStatIter.next();
List<Attribute> attributesList = statment.getAttributes();
Iterator<Attribute> attributesIter = attributesList.iterator();
while (attributesIter.hasNext()) {
Attribute attrib = attributesIter.next();
Element value = attrib.getAttributeValues().get(0).getDOM();
String attribValue = value.getTextContent();
resutls.put(attrib.getName(), attribValue);
}
}
}
}
return resutls;
}
At the com.avis.saml.sso.SAML2ConsumerServlet.doPost(SAML2ConsumerServlet.java:72)
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,
IOException {
String responseMessage = request.getParameter("SAMLResponse");
if (responseMessage != null) { /* response from the identity provider */
Map<String, String> result = consumer.processResponseMessage(responseMessage);
if (result != null && result.size() == 1) {
/*
* No user attributes are returned, so just goto the default
* home page.
*/
response.sendRedirect("home.jsp?subject=" + result.get("Subject"));
} else if (request != null && result.size() > 1) {
/*
* We have received attributes, so lets show them in the
* attribute home page.
*/
String params = "home-attrib.jsp?";
Object[] keys = result.keySet().toArray();
for (int i = 0; i < result.size(); i++) {
String key = (String) keys[i];
String value = (String) result.get(key);
if (i != result.size()) {
params = params + key + "=" + value + "&";
} else {
params = params + key + "=" + value;
}
}
response.sendRedirect(params);
} else {
// something wrong, re-login
response.sendRedirect("index.jsp");
}
} else { /* time to create the authentication request or logout request */
try {
String requestMessage = consumer.buildRequestMessage(request);
response.sendRedirect(requestMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the com.avis.saml.sso.SamlConsumerManager.processResponseMessage(SamlConsumerManager.java:246)
public Map<String, String> processResponseMessage(String responseMessage) {
XMLObject responseXmlObj = null;
try {
responseXmlObj = unmarshall(responseMessage);
} catch (ConfigurationException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnmarshallingException e) {
e.printStackTrace();
}
return getResult(responseXmlObj); // line 246
}
Actually, I have two web pages, but here I mentioned one because they are the same. I'm doing a single sign on project that two service provider (web pages) are central authenticated at WSO2 Identity Server using SAML2.0 and OpenSAML
I don't know whether I miss some step when configure or not? Are there any important point I must keep in mind for my web page to authenticate successfully.
I was getting the same exception.Updating unmarshall method as below resolved my problem.
private XMLObject unmarshall(String responseMessage) throws ConfigurationException,
ParserConfigurationException, SAXException,
IOException, UnmarshallingException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
byte[] base64DecodedResponse = responseMessage.getBytes("UTF-8");
byte[] decoded = Base64.decode(base64DecodedResponse,0,responseMessage.length());
System.out.println(new String(decoded, StandardCharsets.UTF_8));
String s = new String(decoded,StandardCharsets.UTF_8);
Document document = docBuilder.parse(new InputSource(new StringReader(s)));
Element element = document.getDocumentElement();
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);
return unmarshaller.unmarshall(element);
}

Websphere Portal 8 login service check existing password correct

I have a portlet that is used to change the password of the logged in user. The user has to enter their current password and a new password twice. It calls the LoginService.checkPassword(String userId, char[] password) to determine if the existing password is correct. If this method returns true, then the password is updated by getting the current user via the Puma Profile and setting the updated attribute using the PumaController.setAttributes(User user, Map attributes) call. Then the puma profile is reloaded via the PumaProfile.reload method (I've also tried using the PumaController.reload() method.
The problem I'm facing is that the LoginService.checkPassword(String userId, char[] password) is returning true for the current password and also older passwords rather than just for the current password. Does anyone know why this would be?
In ldap the password field is a single attribute field, as it is also in wimdomain.xml, and if I log out and try to log in, I can only log in with the current password (as you would expect).
Found it's a bug in Portal. Even if you use the out of the box profile edit portlet, you get the same issue
Verify Websphere Portal User's Password
There are two ways to verify user's password -
1) Use "UserRegistry"
public static boolean checkUserAuthenticatedLDAP(String userId, String password) {
try {
Context ctx = new InitialContext();
com.ibm.websphere.security.UserRegistry reg =
(com.ibm.websphere.security.UserRegistry) ctx.lookup("UserRegistry");
String res = reg.checkPassword(userId, password);
return res != null;
} catch (Exception ex) {
return false;
}
}
2) Use "LoginContext"
/**
* This method validates the user based on the user id and password
* attributes, If the user id or password is not valid then throws Exception.
*
* #param userId
* #param password
* #return boolean
* #throws Exception
*/
public boolean checkUserAuthenticated(String userId, String password) throws Exception {
javax.security.auth.login.LoginContext loginContext = null;
Subject subject = null;
try {
loginContext = new javax.security.auth.login.LoginContext("WSLogin",
new com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl(userId, password));
} catch (javax.security.auth.login.LoginException e) {
throw new Exception("Cannot create LoginContext", e);
}
try {
loginContext.login();
subject = loginContext.getSubject();
} catch (com.ibm.websphere.security.auth.WSLoginFailedException e) {
throw new Exception("Password is incorrect", e);
} catch (Exception e) {
throw new Exception("Unknown username", e);
}
if (subject == null)
throw new Exception("Password is incorrect");
return true;
}

FBA dual authentication problem

What I have?
I have configured FBA in one of the web applications with out of the box login page having dropdown box to select the either windows or FBA login. Everything is working fine.
What I want?
I want to have a custom login page having text boxes for Username and Password and a login button which will be used for authenticating both Windows and FBA users. To distinguish between the two different logins, I want to handle OnAuthenticate event and check if the user name contains a '\' then assume it is Windows user otherwise, it is FBA user.
This is the code written in OnAuthenticate event handler:
protected void signinControl_Authenticate(object sender, AuthenticateEventArgs e)
{
string fullUserName = signinControl.UserName;
string username = null;
if (fullUserName.Contains("\\")) //Windows user
{
string domain = fullUserName.Substring(0, fullUserName.IndexOf("\\"));
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
username = fullUserName.Substring(fullUserName.IndexOf("\\") + 1);
e.Authenticated = pc.ValidateCredentials(username, signinControl.Password);
}
}
else //FBA user
{
e.Authenticated = Membership.ValidateUser(fullUserName, signinControl.Password);
}
}
What problem am I facing?
The code above works well for FBA Users. But, when I try to login with a windows user, even though the e.Authenticated is set true after validating, it is throwing this error: "Your login attempt was not successful. Please try again.".
e.Authenticated = pc.ValidateCredentials(username, signinControl.Password);
I believe that, setting e.Authenticated to true should redirect the user from login page to the requested page. Can someone please help me if I have to do anything else to get Windows user signed in?
Update-1:
I used SetAuthCookie() method to set Cookie explicitly, still the same result.
FormsAuthentication.SetAuthCookie(username, true);
you should use the methode below for forms user
SPClaimsUtility.AuthenticateFormsUser(
Context.Request.UrlReferrer,
UserName.Text,
Password.Text);
and the windows part is declared like this:
protected void lbInternalUsers_OnClick(object sender, EventArgs e)
{
try
{
if (null != SPContext.Current && null != SPContext.Current.Site)
{
SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];
if (null != iisSettings && iisSettings.UseWindowsClaimsAuthenticationProvider)
{
SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider;
Redirect(provider);
}
}
}
catch (Exception ex)
{
lblError.Text = ex.Message;
}
}
private void Redirect(SPAuthenticationProvider provider)
{
string comp = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);
string url = provider.AuthenticationRedirectionUrl.ToString();
if (provider is SPWindowsAuthenticationProvider)
{
comp = EnsureUrl(comp, true);
}
SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, comp);
}
private string EnsureUrl(string url, bool urlIsQueryStringOnly)
{
if (!url.Contains("ReturnUrl="))
{
if (urlIsQueryStringOnly)
{
url = url + (string.IsNullOrEmpty(url) ? "" : "&");
}
else
{
url = url + ((url.IndexOf('?') == -1) ? "?" : "&");
}
url = url + "ReturnUrl=";
}
return url;
}
as detailed here in the reference