Skip to content

Commit

Permalink
Merge pull request #13460 from lasanthaS/bug-fixing
Browse files Browse the repository at this point in the history
Fix issues in the account-recovery/authentication endpoints
  • Loading branch information
tharikaGitHub committed Apr 2, 2024
2 parents 8b5afd2 + a8d25cb commit 14dce52
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 1 deletion.
2 changes: 2 additions & 0 deletions modules/distribution/product/src/main/assembly/bin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@
<exclude>accountrecoveryendpoint/RecoveryEndpointConfig.properties</exclude>
<exclude>accountrecoveryendpoint/self-registration-complete.jsp</exclude>
<exclude>accountrecoveryendpoint/password-recovery.jsp</exclude>
<exclude>accountrecoveryendpoint/password-reset-complete.jsp</exclude>
<exclude>accountrecoveryendpoint/includes/header.jsp</exclude>
<exclude>accountrecoveryendpoint/includes/title.jsp</exclude>
<exclude>accountrecoveryendpoint/includes/product-footer.jsp</exclude>
Expand Down Expand Up @@ -586,6 +587,7 @@
<includes>
<include>self-registration-complete.jsp</include>
<include>password-recovery.jsp</include>
<include>password-reset-complete.jsp</include>
<include>self-registration-username-request.jsp</include>
<include>self-registration-with-verification.jsp</include>
<include>error.jsp</include>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
<%--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
--%>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%@ page import="org.wso2.carbon.core.SameSiteCookie" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.IdentityManagementEndpointConstants" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.IdentityManagementEndpointUtil" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.ApiException" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.api.NotificationApi" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.Error" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.Property" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.ResetPasswordRequest" %>
<%@ page import="org.wso2.carbon.identity.core.util.IdentityTenantUtil" %>
<%@ page import="java.io.File" %>
<%@ page import="java.net.URISyntaxException" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Map" %>
<%@ page import="javax.servlet.http.Cookie" %>
<%@ page import="java.util.Base64" %>
<%@ page import="org.wso2.carbon.core.util.SignatureUtil" %>
<%@ page import="org.json.simple.JSONObject" %>
<%@ page import="org.owasp.encoder.Encode" %>
<%@ page import="org.wso2.carbon.identity.recovery.util.Utils" %>
<%@ page import="org.apache.http.client.utils.URIBuilder" %>
<%@ page import="java.net.URI" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.model.User" %>
<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.PreferenceRetrievalClient" %>
<%@ taglib prefix="layout" uri="org.wso2.identity.apps.taglibs.layout.controller" %>

<jsp:directive.include file="includes/localize.jsp"/>
<jsp:directive.include file="tenant-resolve.jsp"/>
<jsp:directive.include file="includes/layout-resolver.jsp"/>

<%
String ERROR_MESSAGE = "errorMsg";
String ERROR_CODE = "errorCode";
String PASSWORD_RESET_PAGE = "password-reset.jsp";
String AUTO_LOGIN_COOKIE_NAME = "ALOR";
String AUTO_LOGIN_FLOW_TYPE = "RECOVERY";
String AUTO_LOGIN_COOKIE_DOMAIN = "AutoLoginCookieDomain";
String RECOVERY_TYPE_INVITE = "invite";
String passwordHistoryErrorCode = "22001";
String passwordPatternErrorCode = "20035";
String confirmationKey =
IdentityManagementEndpointUtil.getStringValue(request.getSession().getAttribute("confirmationKey"));
String newPassword = request.getParameter("reset-password");
String callback = request.getParameter("callback");
String userStoreDomain = request.getParameter("userstoredomain");
String type = request.getParameter("type");
String username = null;
PreferenceRetrievalClient preferenceRetrievalClient = new PreferenceRetrievalClient();
Boolean isAutoLoginEnable = preferenceRetrievalClient.checkAutoLoginAfterPasswordRecoveryEnabled(tenantDomain);
String sessionDataKey = StringUtils.EMPTY;
if (StringUtils.isBlank(callback)) {
callback = IdentityManagementEndpointUtil.getUserPortalUrl(
application.getInitParameter(IdentityManagementEndpointConstants.ConfigConstants.USER_PORTAL_URL), tenantDomain);
}
if (StringUtils.isNotBlank(newPassword)) {
NotificationApi notificationApi = new NotificationApi();
ResetPasswordRequest resetPasswordRequest = new ResetPasswordRequest();
List<Property> properties = new ArrayList<Property>();
Property property = new Property();
property.setKey("callback");
property.setValue(URLEncoder.encode(callback, "UTF-8"));
properties.add(property);
Property tenantProperty = new Property();
tenantProperty.setKey(IdentityManagementEndpointConstants.TENANT_DOMAIN);
if (tenantDomain == null) {
tenantDomain = IdentityManagementEndpointConstants.SUPER_TENANT;
}
tenantProperty.setValue(URLEncoder.encode(tenantDomain, "UTF-8"));
properties.add(tenantProperty);
resetPasswordRequest.setKey(confirmationKey);
resetPasswordRequest.setPassword(newPassword);
resetPasswordRequest.setProperties(properties);
try {
User user = notificationApi.setUserPasswordPost(resetPasswordRequest);
username = user.getUsername();
userStoreDomain = user.getRealm();
if (isAutoLoginEnable) {
if (userStoreDomain != null) {
username = userStoreDomain + "/" + username + "@" + tenantDomain;
}
String cookieDomain = application.getInitParameter(AUTO_LOGIN_COOKIE_DOMAIN);
JSONObject contentValueInJson = new JSONObject();
contentValueInJson.put("username", username);
contentValueInJson.put("createdTime", System.currentTimeMillis());
contentValueInJson.put("flowType", AUTO_LOGIN_FLOW_TYPE);
if (StringUtils.isNotBlank(cookieDomain)) {
contentValueInJson.put("domain", cookieDomain);
}
String content = contentValueInJson.toString();
SignatureUtil.init();
JSONObject cookieValueInJson = new JSONObject();
cookieValueInJson.put("content", content);
String signature = Base64.getEncoder().encodeToString(SignatureUtil.doSignature(content));
cookieValueInJson.put("signature", signature);
String cookieValue = Base64.getEncoder().encodeToString(cookieValueInJson.toString().getBytes());
IdentityManagementEndpointUtil.setCookie(request, response, AUTO_LOGIN_COOKIE_NAME, cookieValue,
300, SameSiteCookie.NONE, "/", cookieDomain);
if (callback.contains("?")) {
String queryParams = callback.substring(callback.indexOf("?") + 1);
String[] parameterList = queryParams.split("&");
Map<String, String> queryMap = new HashMap<>();
for (String param : parameterList) {
String key = param.substring(0, param.indexOf("="));
String value = param.substring(param.indexOf("=") + 1);
queryMap.put(key, value);
}
sessionDataKey = queryMap.get("sessionDataKey");
}
}
} catch (ApiException e) {
Error error = IdentityManagementEndpointUtil.buildError(e);
IdentityManagementEndpointUtil.addErrorInformation(request, error);
if (error != null) {
request.setAttribute(ERROR_MESSAGE, error.getDescription());
request.setAttribute(ERROR_CODE, error.getCode());
if (passwordHistoryErrorCode.equals(error.getCode()) ||
passwordPatternErrorCode.equals(error.getCode())) {
String i18Resource = IdentityManagementEndpointUtil.i18n(recoveryResourceBundle, error.getCode());
if (!i18Resource.equals(error.getCode())) {
request.setAttribute(ERROR_MESSAGE, i18Resource);
}
request.setAttribute(IdentityManagementEndpointConstants.TENANT_DOMAIN, tenantDomain);
request.setAttribute(IdentityManagementEndpointConstants.CALLBACK, callback);
request.setAttribute("userstoredomain", userStoreDomain);
request.getRequestDispatcher(PASSWORD_RESET_PAGE).forward(request, response);
return;
}
}
request.getRequestDispatcher("error.jsp").forward(request, response);
return;
}
} else {
request.setAttribute("error", true);
request.setAttribute("errorMsg", IdentityManagementEndpointUtil.i18n(recoveryResourceBundle,
"Password.cannot.be.empty"));
request.setAttribute(IdentityManagementEndpointConstants.TENANT_DOMAIN, tenantDomain);
request.setAttribute(IdentityManagementEndpointConstants.CALLBACK, callback);
request.setAttribute("userstoredomain", userStoreDomain);
request.getRequestDispatcher("password-reset.jsp").forward(request, response);
return;
}
session.invalidate();
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%-- Data for the layout from the page --%>
<%
layoutData.put("containerSize", "medium");
%>

<!doctype html>
<html lang="en-US">
<head>
<%
File headerFile = new File(getServletContext().getRealPath("extensions/header.jsp"));
if (headerFile.exists()) {
%>
<jsp:include page="extensions/header.jsp"/>
<% } else { %>
<jsp:include page="includes/header.jsp"/>
<% } %>
</head>
<body class="login-portal layout">
<% if (!RECOVERY_TYPE_INVITE.equalsIgnoreCase(type)) { %>
<div>
<form id="callbackForm" name="callbackForm" method="post" action="/commonauth">
<div>
<input type="hidden" name="username" value="<%=Encode.forHtmlAttribute(username)%>"/>
</div>
<div>
<input type="hidden" name="sessionDataKey" value="<%=Encode.forHtmlAttribute(sessionDataKey)%>"/>
</div>
</form>
</div>
<% } %>

<layout:main layoutName="<%= layout %>" layoutFileRelativePath="<%= layoutFileRelativePath %>" data="<%= layoutData %>" >
<layout:component componentName="ProductHeader" >
<!-- product-title -->
<% if (RECOVERY_TYPE_INVITE.equalsIgnoreCase(type)) {
File productTitleFile = new File(getServletContext().getRealPath("extensions/product-title.jsp"));
if (productTitleFile.exists()) {
%>
<jsp:include page="extensions/product-title.jsp"/>
<% } else { %>
<jsp:include page="includes/product-title.jsp"/>
<% }
} %>
</layout:component>
<layout:component componentName="MainSection" >
<% if (RECOVERY_TYPE_INVITE.equalsIgnoreCase(type)) { %>
<div class="ui green segment mt-3 attached">
<h3 class="ui header text-center slogan-message mt-4 mb-6" data-testid="password-reset-complete-page-header">
Password Set Sucessfully
</h3>
<p style="padding-right: 90px; padding-left: 90px">
You have successfully set a password for your account <b><%=username%></b>.
</p>
</div>
<% } %>
</layout:component>
<layout:component componentName="ProductFooter" >
<!-- product-footer -->
<% if (RECOVERY_TYPE_INVITE.equalsIgnoreCase(type)) {
File productFooterFile = new File(getServletContext().getRealPath("extensions/product-footer.jsp"));
if (productFooterFile.exists()) {
%>
<jsp:include page="extensions/product-footer.jsp"/>
<% } else { %>
<jsp:include page="includes/product-footer.jsp"/>
<% }
} %>
</layout:component>
</layout:main>

<%-- footer --%>
<%
File footerFile = new File(getServletContext().getRealPath("extensions/footer.jsp"));
if (footerFile.exists()) {
%>
<jsp:include page="extensions/footer.jsp"/>
<% } else { %>
<jsp:include page="includes/footer.jsp"/>
<% } %>

<script type="application/javascript">
$(document).ready(function () {
<%
try {
if (!RECOVERY_TYPE_INVITE.equalsIgnoreCase(type)) {
if (isAutoLoginEnable && StringUtils.isNotBlank(sessionDataKey) && (StringUtils.isNotBlank(username))) {
%>
document.callbackForm.submit();
<%
} else {
URIBuilder callbackUrlBuilder = new
URIBuilder(IdentityManagementEndpointUtil.encodeURL(callback));
URI callbackUri = callbackUrlBuilder.addParameter("passwordReset", "true").build();
%>
location.href = "<%=callbackUri.toString()%>";
<%
}
}
} catch (URISyntaxException e) {
request.setAttribute("error", true);
request.setAttribute("errorMsg", "Invalid callback URL found in the request.");
request.getRequestDispatcher("error.jsp").forward(request, response);
return;
}
%>
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<% if ("API Manager".equals(request.getAttribute("headerTitle"))) { %>
<div class="product-title">
<div class="theme-icon inline auto transparent product-logo">
<div class="theme-icon inline auto transparent product-logo" style="margin: 0;">
<svg viewBox="29 -6.639 72 27.639">
<circle fill="#F47B20" cx="82.076" cy="4.192" r="8.691"></circle>
<path fill="#FFF" d="M90.804 3.776l-.01-.115h-3.375l-.035.063c-.402.711-.798 1.425-1.193 2.14l-.348.626c-.601-1.454-1.198-2.908-1.795-4.363-.63-1.535-1.26-3.07-1.895-4.603l-.11-.266-.119.262A631.674 631.674 0 0080.565.541a479.296 479.296 0 01-1.905 4.212c-.897-.008-1.794-.007-2.695-.006-.823.001-1.648.002-2.475-.004l-.128-.001.002.128c.004.278.044.554.083.821l.021.148h.108c1.432-.002 2.863-.002 4.293-.001h1.512l.034-.073c.44-.972.878-1.947 1.316-2.921.421-.938.842-1.875 1.267-2.811.643 1.552 1.279 3.106 1.917 4.661.558 1.359 1.115 2.719 1.677 4.077l.098.237.127-.224c.576-1.025 1.147-2.054 1.719-3.082l.528-.951h2.74l.01-.115c.02-.253.017-.527-.01-.86z"></path>
Expand Down

0 comments on commit 14dce52

Please sign in to comment.