Skip to content

Commit ec999c3

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 91744b2 + 7bcafbc commit ec999c3

3 files changed

Lines changed: 391 additions & 72 deletions

File tree

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package it.eng.spagobi.commons.services;
2+
3+
import java.net.URL;
4+
import java.text.SimpleDateFormat;
5+
import java.util.ArrayList;
6+
import java.util.Calendar;
7+
import java.util.Collections;
8+
import java.util.Date;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
import javax.servlet.http.HttpServletRequest;
13+
import javax.ws.rs.POST;
14+
import javax.ws.rs.Path;
15+
import javax.ws.rs.Produces;
16+
import javax.ws.rs.core.Context;
17+
import javax.ws.rs.core.MediaType;
18+
import javax.ws.rs.core.Response;
19+
20+
import org.apache.commons.lang3.StringUtils;
21+
import org.apache.log4j.Logger;
22+
23+
import com.auth0.jwt.exceptions.TokenExpiredException;
24+
25+
import it.eng.spago.error.EMFErrorSeverity;
26+
import it.eng.spago.error.EMFUserError;
27+
import it.eng.spagobi.commons.bo.Config;
28+
import it.eng.spagobi.commons.constants.SpagoBIConstants;
29+
import it.eng.spagobi.commons.dao.DAOFactory;
30+
import it.eng.spagobi.commons.dao.IConfigDAO;
31+
import it.eng.spagobi.commons.metadata.SbiCommonInfo;
32+
import it.eng.spagobi.commons.utilities.StringUtilities;
33+
import it.eng.spagobi.commons.validation.PasswordChecker;
34+
import it.eng.spagobi.profiling.bean.SbiUser;
35+
import it.eng.spagobi.profiling.dao.ISbiUserDAO;
36+
import it.eng.spagobi.security.Password;
37+
import it.eng.spagobi.services.rest.annotations.PublicService;
38+
import it.eng.spagobi.signup.validation.SignupJWTTokenManager;
39+
40+
@Path("/resetPassword")
41+
public class ForgotPasswordResource {
42+
43+
private static final Logger LOGGER = Logger.getLogger(ForgotPasswordResource.class);
44+
45+
@POST
46+
@Path("/sendEmail")
47+
@PublicService
48+
@Produces(MediaType.APPLICATION_JSON)
49+
public Response sendEmail(@Context HttpServletRequest req, Map<String, String> payload) {
50+
51+
String mail = payload.get("mail");
52+
53+
if (StringUtils.isBlank(mail)) {
54+
return Response.ok(Map.of("message", "Reset email sent successfully")).build();
55+
}
56+
57+
ISbiUserDAO userDao = DAOFactory.getSbiUserDAO();
58+
ArrayList<SbiUser> lstUser = userDao.loadSbiUserFromEmail(mail);
59+
60+
if (lstUser == null || lstUser.isEmpty()) {
61+
return Response.ok(Map.of("message", "Reset email sent successfully")).build();
62+
}
63+
64+
if (lstUser.size() > 1) {
65+
LOGGER.warn("Multiple users found for email: " + mail);
66+
return Response.ok(Map.of("message", "Reset email sent successfully")).build();
67+
}
68+
69+
try {
70+
SbiUser user = lstUser.get(0);
71+
72+
String token = SignupJWTTokenManager.createJWTToken(user.getUserId());
73+
String version = SbiCommonInfo.getVersion().substring(0, SbiCommonInfo.getVersion().lastIndexOf("."));
74+
75+
String resetUrl = buildResetPasswordUrl(req, token, version);
76+
String mailSubject = "Password Reset Request";
77+
String mailBody = buildResetPasswordEmailBody(resetUrl);
78+
79+
sendMail(mail, mailSubject, mailBody);
80+
81+
return Response.ok(Map.of("message", "Reset email sent successfully")).build();
82+
83+
} catch (Exception e) {
84+
LOGGER.error("An unexpected error occurred while executing the sendEmail", e);
85+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(Map.of("error", "An error occurred while sending reset email")).build();
86+
}
87+
}
88+
89+
@POST
90+
@Path("/verifyToken")
91+
@PublicService
92+
@Produces(MediaType.APPLICATION_JSON)
93+
public Response veifyToken(@Context HttpServletRequest req, Map<String, String> payload) {
94+
95+
String token = payload.get("token");
96+
97+
if (StringUtils.isBlank(token)) {
98+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "Token is mandatory")).build();
99+
}
100+
101+
try {
102+
String userId = SignupJWTTokenManager.verifyJWTToken(token);
103+
104+
ISbiUserDAO userDao = DAOFactory.getSbiUserDAO();
105+
SbiUser user = userDao.loadSbiUserByUserId(userId);
106+
107+
if (user == null) {
108+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "User not found")).build();
109+
}
110+
111+
return Response.ok(Map.of("message", "Token validated successfully", "userId", userId)).build();
112+
113+
} catch (TokenExpiredException te) {
114+
LOGGER.error("Expired Token [" + token + "]", te);
115+
return Response.status(Response.Status.UNAUTHORIZED).entity(Map.of("error", "Token expired")).build();
116+
} catch (Exception e) {
117+
LOGGER.error("Generic token validation error [" + token + "]", e);
118+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "Invalid token")).build();
119+
}
120+
}
121+
122+
@POST
123+
@Path("/passwordChange")
124+
@PublicService
125+
@Produces(MediaType.APPLICATION_JSON)
126+
public Response passwordChange(@Context HttpServletRequest req, Map<String, String> payload) {
127+
128+
String password = payload.get("password");
129+
String confirmPassword = payload.get("confirmPassword");
130+
String token = payload.get("token");
131+
132+
// Validate password inputs
133+
Response validationError = validatePasswordInput(password, confirmPassword);
134+
if (validationError != null) {
135+
return validationError;
136+
}
137+
138+
// Verify token and get user
139+
try {
140+
String userId = SignupJWTTokenManager.verifyJWTToken(token);
141+
ISbiUserDAO userDao = DAOFactory.getSbiUserDAO();
142+
SbiUser user = userDao.loadSbiUserByUserId(userId);
143+
144+
if (user == null) {
145+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "User not found")).build();
146+
}
147+
148+
// Update user password and expiration date
149+
updateUserPassword(user, password);
150+
userDao.updateSbiUser(user, user.getId());
151+
152+
return Response.ok(Map.of("message", "Password changed successfully")).build();
153+
154+
} catch (TokenExpiredException te) {
155+
LOGGER.error("Expired Token [" + token + "]", te);
156+
return Response.status(Response.Status.UNAUTHORIZED).entity(Map.of("error", "Token expired")).build();
157+
} catch (Exception e) {
158+
LOGGER.error("An unexpected error occurred while changing password", e);
159+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(Map.of("error", "An error occurred while changing password")).build();
160+
}
161+
}
162+
163+
private Response validatePasswordInput(String password, String confirmPassword) {
164+
if (StringUtils.isBlank(password) || StringUtils.isBlank(confirmPassword)) {
165+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "Password and confirm password are mandatory")).build();
166+
}
167+
168+
if (!password.equals(confirmPassword)) {
169+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "Passwords do not match")).build();
170+
}
171+
172+
try {
173+
PasswordChecker.getInstance().isValid(password, password);
174+
} catch (Exception e) {
175+
LOGGER.error("Password is not valid", e);
176+
return Response.status(Response.Status.BAD_REQUEST).entity(Map.of("error", "Password is not valid")).build();
177+
}
178+
179+
return null;
180+
}
181+
182+
private void updateUserPassword(SbiUser user, String password) throws Exception {
183+
Date currentDate = new Date();
184+
user.setDtLastAccess(currentDate);
185+
user.setPassword(Password.hashPassword(password));
186+
user.setFlgPwdBlocked(false);
187+
188+
// Set password expiration date if configured
189+
setPasswordExpirationDate(user, currentDate);
190+
}
191+
192+
private void setPasswordExpirationDate(SbiUser user, Date beginDate) throws EMFUserError, Exception {
193+
IConfigDAO configDao = DAOFactory.getSbiConfigDAO();
194+
List<Config> lstConfigChecks = configDao.loadConfigParametersByProperties(SpagoBIConstants.CHANGEPWD_EXPIRED_TIME);
195+
196+
if (lstConfigChecks.isEmpty()) {
197+
return;
198+
}
199+
200+
Config config = lstConfigChecks.get(0);
201+
if (!config.isActive()) {
202+
return;
203+
}
204+
205+
try {
206+
String dateFormat = "yyyy-MM-dd";
207+
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
208+
Calendar cal = Calendar.getInstance();
209+
cal.set(beginDate.getYear() + 1900, beginDate.getMonth(), beginDate.getDate());
210+
cal.add(Calendar.DATE, Integer.parseInt(config.getValueCheck()));
211+
212+
Date endDate = StringUtilities.stringToDate(sdf.format(cal.getTime()), dateFormat);
213+
LOGGER.debug("End Date for expiration calculated: " + endDate);
214+
215+
user.setDtPwdBegin(beginDate);
216+
user.setDtPwdEnd(endDate);
217+
} catch (Exception e) {
218+
LOGGER.error("Error while calculating password expiration date: " + e);
219+
throw new EMFUserError(EMFErrorSeverity.ERROR, 14008, Collections.emptyList(), Collections.emptyMap());
220+
}
221+
}
222+
223+
private String buildResetPasswordUrl(HttpServletRequest req, String token, String version) throws Exception {
224+
String urlString = req.getContextPath() + "/restful-services/signup/changePasswordMail?token=" + token + "&version=" + version;
225+
URL url = new URL(req.getScheme(), req.getServerName(), req.getServerPort(), urlString);
226+
return url.toString();
227+
}
228+
229+
private String buildResetPasswordEmailBody(String resetUrl) {
230+
StringBuilder body = new StringBuilder();
231+
body.append("Please click the link below to reset your password:<br><br>");
232+
body.append("<a href=\"").append(resetUrl).append("\">Reset Password</a><br><br>");
233+
body.append("If you did not request a password reset, please ignore this email.");
234+
return body.toString();
235+
}
236+
237+
private void sendMail(String emailAddress, String subject, String emailContent) throws Exception {
238+
239+
it.eng.knowage.mailsender.dto.MessageMailDto messageMailDto = new it.eng.knowage.mailsender.dto.MessageMailDto();
240+
messageMailDto.setProfileName(it.eng.knowage.mailsender.dto.ProfileNameMailEnum.USER);
241+
messageMailDto.setTypeMailEnum(it.eng.knowage.mailsender.dto.TypeMailEnum.CONTENT);
242+
messageMailDto.setSubject(subject);
243+
messageMailDto.setText(emailContent);
244+
messageMailDto.setContentType("text/html");
245+
messageMailDto.setRecipients(new String[] { emailAddress });
246+
247+
it.eng.knowage.mailsender.factory.FactoryMailSender.getMailSender(it.eng.spagobi.commons.SingletonConfig.getInstance().getConfigValue(it.eng.knowage.mailsender.IMailSender.MAIL_SENDER)).sendMail(messageMailDto);
248+
249+
}
250+
251+
}

knowage-core/src/main/java/it/eng/spagobi/commons/services/LoginConfigResource.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ public class LoginConfigResource extends AbstractSpagoBIResource {
3030
public Response getLoginConfig(@Context HttpServletRequest req) {
3131
IKnowageMonitor monitor = KnowageMonitorFactory.getInstance().start("knowage.login.config.load");
3232
try {
33-
String activeStr = SingletonConfig.getInstance().getConfigValue("SPAGOBI_SSO.ACTIVE");
34-
String flowType = Optional.ofNullable(System.getProperty("oauth2_flow_type", System.getenv("OAUTH2_FLOW_TYPE")))
35-
.orElse("");
3633

37-
Map<String, Object> item = new HashMap<>();
38-
item.put("ssoActive", activeStr);
39-
item.put("oauth2FlowType", flowType);
34+
SingletonConfig config = SingletonConfig.getInstance();
35+
36+
Map<String, Object> item = new HashMap<>();
37+
item.put("ssoActive", config.getConfigValue("SPAGOBI_SSO.ACTIVE"));
38+
item.put("defaultLanguage", config.getConfigValue("SPAGOBI.LANGUAGE_SUPPORTED.LANGUAGE.default"));
39+
item.put("oauth2FlowType", Optional.ofNullable(System.getProperty("oauth2_flow_type", System.getenv("OAUTH2_FLOW_TYPE"))).orElse(""));
4040

4141
monitor.stop();
4242
return Response.ok(Map.of("items", List.of(item))).build();

0 commit comments

Comments
 (0)