diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bef5a3018764255a9e1112126180cf902b12b629..4d016a30e5e11b580e52bf5e0ae8bda42273c890 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -97,68 +97,68 @@ dockerize genesys branch: - tags -deploy for review: - stage: deploy - image: docker:${DOCKER_VERSION} - except: - - master - - /^production-.*/ - # when: manual - allow_failure: false - environment: - name: genesys/${CI_COMMIT_REF_SLUG} - url: https://${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org - on_stop: remove review instance - script: - # Address the swarm - - export DOCKER_HOST=swarm.genesys-pgr.org - # Configuration - - TLS_PATH=~/.docker/${DOCKER_HOST}/certs && mkdir -p ${TLS_PATH} - - echo "${DOCKER_TLS_CA}" > ${TLS_PATH}/ca.pem - - echo "${DOCKER_TLS_KEY}" > ${TLS_PATH}/key.pem - - echo "${DOCKER_TLS_CERT}" > ${TLS_PATH}/cert.pem - - export DOCKER_TLS_VERIFY=1 - - export DOCKER_CERT_PATH=${TLS_PATH} - - DOCKER_CMD=docker - # Actions - - apk add --no-cache gettext - - if [ "${CI_COMMIT_REF_SLUG}" = "master" ] ; then - export IMAGE_TAG="${GENESYS_VERSION}"; - else - export IMAGE_TAG="${GENESYS_VERSION}-${CI_COMMIT_REF_SLUG}"; - fi - - echo Deploying ${CI_REGISTRY_IMAGE}:${IMAGE_TAG} for review as https\://${CI_ENVIRONMENT_SLUG}.review.genesys\-pgr.org - - envsubst < docker/review-compose-template.yml > review-composed.yml - # - cat review-composed.yml - - ${DOCKER_CMD} stack rm ${CI_ENVIRONMENT_SLUG} || true - - ${DOCKER_CMD} stack deploy -c review-composed.yml ${CI_ENVIRONMENT_SLUG} +# deploy for review: +# stage: deploy +# image: docker:${DOCKER_VERSION} +# except: +# - master +# - /^production-.*/ +# # when: manual +# allow_failure: false +# environment: +# name: genesys/${CI_COMMIT_REF_SLUG} +# url: https://${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org +# on_stop: remove review instance +# script: +# # Address the swarm +# - export DOCKER_HOST=swarm.genesys-pgr.org +# # Configuration +# - TLS_PATH=~/.docker/${DOCKER_HOST}/certs && mkdir -p ${TLS_PATH} +# - echo "${DOCKER_TLS_CA}" > ${TLS_PATH}/ca.pem +# - echo "${DOCKER_TLS_KEY}" > ${TLS_PATH}/key.pem +# - echo "${DOCKER_TLS_CERT}" > ${TLS_PATH}/cert.pem +# - export DOCKER_TLS_VERIFY=1 +# - export DOCKER_CERT_PATH=${TLS_PATH} +# - DOCKER_CMD=docker +# # Actions +# - apk add --no-cache gettext +# - if [ "${CI_COMMIT_REF_SLUG}" = "master" ] ; then +# export IMAGE_TAG="${GENESYS_VERSION}"; +# else +# export IMAGE_TAG="${GENESYS_VERSION}-${CI_COMMIT_REF_SLUG}"; +# fi +# - echo Deploying ${CI_REGISTRY_IMAGE}:${IMAGE_TAG} for review as https\://${CI_ENVIRONMENT_SLUG}.review.genesys\-pgr.org +# - envsubst < docker/review-compose-template.yml > review-composed.yml +# # - cat review-composed.yml +# - ${DOCKER_CMD} stack rm ${CI_ENVIRONMENT_SLUG} || true +# - ${DOCKER_CMD} stack deploy -c review-composed.yml ${CI_ENVIRONMENT_SLUG} -remove review instance: - stage: deploy - image: docker:${DOCKER_VERSION} - except: - - master - - /^production-.*/ - when: manual - variables: - GIT_STRATEGY: none - environment: - name: genesys/${CI_COMMIT_REF_SLUG} - action: stop - script: - - echo Removing review https\://${CI_ENVIRONMENT_SLUG}.review.genesys\-pgr.org - # Address the swarm - - export DOCKER_HOST=swarm.genesys-pgr.org - # Configuration - - TLS_PATH=~/.docker/${DOCKER_HOST}/certs && mkdir -p ${TLS_PATH} - - echo "${DOCKER_TLS_CA}" > ${TLS_PATH}/ca.pem - - echo "${DOCKER_TLS_KEY}" > ${TLS_PATH}/key.pem - - echo "${DOCKER_TLS_CERT}" > ${TLS_PATH}/cert.pem - - export DOCKER_TLS_VERIFY=1 - - export DOCKER_CERT_PATH=${TLS_PATH} - - DOCKER_CMD=docker - # Actions - - ${DOCKER_CMD} stack rm ${CI_ENVIRONMENT_SLUG} || true +# remove review instance: +# stage: deploy +# image: docker:${DOCKER_VERSION} +# except: +# - master +# - /^production-.*/ +# when: manual +# variables: +# GIT_STRATEGY: none +# environment: +# name: genesys/${CI_COMMIT_REF_SLUG} +# action: stop +# script: +# - echo Removing review https\://${CI_ENVIRONMENT_SLUG}.review.genesys\-pgr.org +# # Address the swarm +# - export DOCKER_HOST=swarm.genesys-pgr.org +# # Configuration +# - TLS_PATH=~/.docker/${DOCKER_HOST}/certs && mkdir -p ${TLS_PATH} +# - echo "${DOCKER_TLS_CA}" > ${TLS_PATH}/ca.pem +# - echo "${DOCKER_TLS_KEY}" > ${TLS_PATH}/key.pem +# - echo "${DOCKER_TLS_CERT}" > ${TLS_PATH}/cert.pem +# - export DOCKER_TLS_VERIFY=1 +# - export DOCKER_CERT_PATH=${TLS_PATH} +# - DOCKER_CMD=docker +# # Actions +# - ${DOCKER_CMD} stack rm ${CI_ENVIRONMENT_SLUG} || true deploy on staging server: stage: deploy diff --git a/src/main/java/org/genesys2/server/listener/sample/CreateContentListener.java b/src/main/java/org/genesys2/server/listener/sample/CreateContentListener.java index f8aa97527019b949f75ba237972a11fc44a101e4..085ed05cff7e6789f9bd0abc83614f833f099398 100644 --- a/src/main/java/org/genesys2/server/listener/sample/CreateContentListener.java +++ b/src/main/java/org/genesys2/server/listener/sample/CreateContentListener.java @@ -73,12 +73,12 @@ public class CreateContentListener extends RunAsAdminListener { } private void createArticles() throws IOException, JsonProcessingException { - if (!createContent) { - LOG.warn("Skipping content creation on startup."); - return; - } +// if (!createContent) { +// LOG.warn("Skipping content creation on startup."); +// return; +// } - LOG.debug("Checking if default content exists"); + LOG.info("Checking if default content exists"); final ClassLoader classLoader = CreateContentListener.class.getClassLoader(); final PathMatchingResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(classLoader); final String resourcePath = "/default-content/*"; @@ -90,10 +90,18 @@ public class CreateContentListener extends RunAsAdminListener { final ObjectMapper mapper = new ObjectMapper(); try (InputStream stream = r.getInputStream()) { final JsonNode json = mapper.readTree(stream); + + JsonNode templateNode = json.get("template"); + final boolean isTemplate = templateNode != null && templateNode.booleanValue(); final Iterator> it = json.fields(); while (it.hasNext()) { final Entry entry = it.next(); + + if (entry.getKey().length() != 2) { + // Skip over non-language fields + continue; + } final Locale locale = new Locale(entry.getKey()); // Load from default locale if exists @@ -102,10 +110,10 @@ public class CreateContentListener extends RunAsAdminListener { // If nothing is found, parse the resource and create content if (article == null) { try { - contentService.createGlobalArticle(slug, locale, entry.getValue().get("title").asText(), entry.getValue().get("body").asText(), null, false); - LOG.info("Created article for slug: {} lang={}", slug, locale.getLanguage()); + contentService.createGlobalArticle(slug, locale, entry.getValue().get("title").asText(), entry.getValue().get("body").asText(), null, isTemplate); + LOG.warn("Created article for slug: {} lang={}", slug, locale.getLanguage()); } catch (CRMException e) { - LOG.warn("Failed to create global article slug={}.", slug, e); + LOG.error("Failed to create global article slug={}.", slug, e); } } } diff --git a/src/main/java/org/genesys2/server/service/ContentService.java b/src/main/java/org/genesys2/server/service/ContentService.java index c50ca8cfa01746552674973de3025541cf59a7be..97c64da9b3370990bc6cedaf11d2be677fb42bd1 100644 --- a/src/main/java/org/genesys2/server/service/ContentService.java +++ b/src/main/java/org/genesys2/server/service/ContentService.java @@ -60,6 +60,11 @@ public interface ContentService { public final String USER_PASSWORD_RESET = "user-password-reset"; public final String USER_PASSWORD_RESET_EMAIL_SENT = "user-password-reset-email-sent"; public final String USER_RESET_PASSWORD_INSTRUCTIONS = "user-reset-password-instructions"; + public final String DELETE_ACCOUNT = "user-delete-account"; + public final String SMTP_DELETE_ACCOUNT = "smtp-delete-account"; + public final String DELETE_ACCOUNT_SENT = "account-delete-requested"; + public final String DELETE_ACCOUNT_CONFIRMED = "account-delete-confirmed"; + public final String SMTP_DELETE_ACCOUNT_INPROGRESS = "smtp-delete-account-inprogress"; List lastNews(); diff --git a/src/main/java/org/genesys2/server/service/EMailVerificationService.java b/src/main/java/org/genesys2/server/service/EMailVerificationService.java index 328178120d727bffa237d2a52fbebd4c041ac3bb..68c27964576f9502afb29d8582f7deecc874f4f6 100644 --- a/src/main/java/org/genesys2/server/service/EMailVerificationService.java +++ b/src/main/java/org/genesys2/server/service/EMailVerificationService.java @@ -16,6 +16,7 @@ package org.genesys2.server.service; +import org.genesys.blocks.security.UserException; import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException; import org.genesys2.server.model.impl.User; import org.genesys2.server.service.TokenVerificationService.NoSuchVerificationTokenException; @@ -32,4 +33,8 @@ public interface EMailVerificationService { void validateEMail(String tokenUuid, String key) throws NoSuchVerificationTokenException, TokenExpiredException; void changePassword(String tokenUuid, String key, String password) throws NoSuchVerificationTokenException, PasswordPolicyException, TokenExpiredException; + + void requestDeleteAccount(User user); + + void confirmDeleteAccount(String tokenUuid, String key) throws NoSuchVerificationTokenException, TokenExpiredException, UserException; } diff --git a/src/main/java/org/genesys2/server/service/UserService.java b/src/main/java/org/genesys2/server/service/UserService.java index 50cce34546def33182cbf75aa9b7ad34731b13ad..a8a7e58ca33a6e966e45e181da3eead841602c6f 100644 --- a/src/main/java/org/genesys2/server/service/UserService.java +++ b/src/main/java/org/genesys2/server/service/UserService.java @@ -66,4 +66,17 @@ public interface UserService extends BasicUserService { void setFtpPassword(User user, String ftpPassword) throws PasswordPolicyException; + /** + * Disables current user's account + * @throws UserException + */ + void disableMyAccount() throws UserException; + + /** + * Disables the account and removes personally identifiable data. + * + * @param user + * @throws UserException + */ + void archiveUser(User user) throws UserException; } diff --git a/src/main/java/org/genesys2/server/service/impl/EMailVerificationServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/EMailVerificationServiceImpl.java index 495f34ad8ff63a69934bdc0cfa1c4c22cf3499e1..3cc2fec82e56521c692b1313dafaf814c9637a32 100644 --- a/src/main/java/org/genesys2/server/service/impl/EMailVerificationServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/EMailVerificationServiceImpl.java @@ -19,6 +19,8 @@ package org.genesys2.server.service.impl; import java.text.MessageFormat; import java.util.Locale; +import org.genesys.blocks.security.SecurityContextUtil; +import org.genesys.blocks.security.UserException; import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException; import org.genesys2.server.model.impl.Article; import org.genesys2.server.model.impl.User; @@ -61,6 +63,9 @@ public class EMailVerificationServiceImpl implements EMailVerificationService { @Value("${base.url}") private String baseUrl; + @Value("${mail.user.from}") + private String defaultEmailFrom; + @Override @Transactional public void sendVerificationEmail(User user) { @@ -81,7 +86,7 @@ public class EMailVerificationServiceImpl implements EMailVerificationService { @Override @Transactional public void sendPasswordResetEmail(User user) { - + // Generate new token final VerificationToken verificationToken = tokenVerificationService.generateToken("email-password", user.getUuid()); final Article article = contentService.getGlobalArticle(ContentService.SMTP_EMAIL_PASSWORD, Locale.ENGLISH); @@ -132,4 +137,36 @@ public class EMailVerificationServiceImpl implements EMailVerificationService { } } + @Override + @Transactional + public void requestDeleteAccount(User user) { + // Generate new token + final VerificationToken verificationToken = tokenVerificationService.generateToken("delete-account", user.getUuid()); + final Article article = contentService.getGlobalArticle(ContentService.SMTP_DELETE_ACCOUNT, Locale.ENGLISH); + + final String mailBody = MessageFormat.format(article.getBody(), baseUrl, verificationToken.getUuid(), verificationToken.getKey(), user.getFullName(), user.getEmail()); + + emailService.sendMail(article.getTitle(), mailBody, user.getEmail()); + } + + @Override + @Transactional(rollbackFor = Throwable.class) + public void confirmDeleteAccount(String tokenUuid, String key) throws NoSuchVerificationTokenException, TokenExpiredException, UserException { + final VerificationToken consumedToken = tokenVerificationService.consumeToken("delete-account", tokenUuid, key); + String uuid = consumedToken.getData(); + User currentUser = SecurityContextUtil.getCurrentUser(); + if (currentUser.getUuid().equals(uuid)) { + + userService.disableMyAccount(); + + final Article article = contentService.getGlobalArticle(ContentService.SMTP_DELETE_ACCOUNT_INPROGRESS, Locale.ENGLISH); + + final String mailBody = MessageFormat.format(article.getBody(), baseUrl, currentUser.getFullName(), currentUser.getEmail()); + + emailService.sendMail(article.getTitle(), mailBody, defaultEmailFrom, currentUser.getEmail()); + + } else { + throw new NoSuchVerificationTokenException(); + } + } } diff --git a/src/main/java/org/genesys2/server/service/impl/UserServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/UserServiceImpl.java index 1a2ffafa2ca07935df26b88edcce92e5c06cdc90..6aa1548f668c15718daa6b0b211fd89c48d8407b 100644 --- a/src/main/java/org/genesys2/server/service/impl/UserServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/UserServiceImpl.java @@ -18,7 +18,9 @@ package org.genesys2.server.service.impl; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -384,4 +386,54 @@ public class UserServiceImpl extends BasicUserServiceImpl implem user.setFtpPassword(passwordEncoder.encode(ftpPassword)); userRepository.save(user); } + + @Override + @Transactional + @PreAuthorize("isFullyAuthenticated()") + public void disableMyAccount() throws UserException { + User currentUser = SecurityContextUtil.getMe(); + + User u = userRepository.findOne(currentUser.getId()); + + if (u.hasRole(UserRole.ADMINISTRATOR.getName())) { + throw new UserException("Refusing to disable active administrator account"); + } + + Calendar expires = Calendar.getInstance(); + expires.add(Calendar.MONTH, 1); + u.setAccountExpires(expires.getTime()); + u.setActive(false); + // u.setAccountType(AccountType.DELETED); + + userRepository.save(u); + } + + @Override + @Transactional + public void archiveUser(User user) throws UserException { + user = userRepository.findOne(user.getId()); + + if (user.hasRole(UserRole.ADMINISTRATOR.getName())) { + throw new UserException("Refusing to disable active administrator account"); + } + + LOG.warn("Archiving user {}", user.getEmail()); + Date now = new Date(); + user.setAccountExpires(now); + user.setActive(false); + user.setAccountType(AccountType.LOCAL); + // user.setAccountType(AccountType.DELETED); + user.setEmail("deleted@" + now.getTime()); + user.setPassword(THIS_IS_NOT_A_PASSWORD); + user.setFtpPassword(null); + user.setFullName("USER ACCOUNT DELETED"); + user.setShortName("deleted" + now.getTime()); + user.setPasswordExpires(now); + user.getRoles().clear(); + + userRepository.save(user); + + LOG.warn("Removing ACL entries for {}", user.getEmail()); + aclEntryRepository.delete(user.getAclEntries()); + } } diff --git a/src/main/java/org/genesys2/server/servlet/controller/ArticleController.java b/src/main/java/org/genesys2/server/servlet/controller/ArticleController.java index 02cf98266b23331e2e87ac8a9ed5b1d440f5991a..7d19e68624e2872a2aca16220d6b3ddd75ed8628 100644 --- a/src/main/java/org/genesys2/server/servlet/controller/ArticleController.java +++ b/src/main/java/org/genesys2/server/servlet/controller/ArticleController.java @@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; +import org.springframework.http.MediaType; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; @@ -50,10 +51,12 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; @Controller @RequestMapping("/content") @@ -346,6 +349,28 @@ public class ArticleController extends BaseController { return "/content/article-edit"; } + @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") + @RequestMapping(value = "/edit/{url}/{language}", produces = MediaType.APPLICATION_JSON_VALUE, params = { "json" }) + public @ResponseBody Object articleAsJson(ModelMap model, @PathVariable(value = "url") String slug, @PathVariable("language") String language) { + Article article = contentService.getArticleBySlugAndLang(slug, language); + if (article == null) { + article = new Article(); + article.setSlug(slug); + article.setLang(language); + } + model.addAttribute("article", article); + + ObjectMapper mapper=new ObjectMapper(); + ObjectNode node = mapper.createObjectNode(); + node.put("template", article.isTemplate()); + ObjectNode lang = node.putObject(language); + lang.put("title", article.getTitle()); + lang.put("body", article.getBody()); + + return node; + } + + /** * Edit article in another language * diff --git a/src/main/java/org/genesys2/server/servlet/controller/UserProfileController.java b/src/main/java/org/genesys2/server/servlet/controller/UserProfileController.java index 23ab2b6f9980b55f18a3a3b4630b5f39a4410caf..08bce7dfc6a60e0ed191f82943bfcd3e026973bc 100644 --- a/src/main/java/org/genesys2/server/servlet/controller/UserProfileController.java +++ b/src/main/java/org/genesys2/server/servlet/controller/UserProfileController.java @@ -17,9 +17,11 @@ package org.genesys2.server.servlet.controller; import java.io.IOException; +import java.util.Locale; import java.util.Random; import java.util.Set; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; @@ -49,7 +51,9 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -317,6 +321,38 @@ public class UserProfileController extends BaseController { return "redirect:/profile/" + user.getUuid(); } + @GetMapping("/me/delete") + @PreAuthorize("isFullyAuthenticated()") + public String startDelete(ModelMap model, Locale locale) { + model.addAttribute("info", contentService.getGlobalArticle(ContentService.DELETE_ACCOUNT, locale)); + return "/user/delete"; + } + + @PostMapping("/me/delete") + @PreAuthorize("isFullyAuthenticated()") + public String requestDelete(ModelMap model) { + final User user = userService.getMe(); + if (user == null) { + throw new ResourceNotFoundException(); + } + + emailVerificationService.requestDeleteAccount(user); + + return "redirect:/content/" + ContentService.DELETE_ACCOUNT_SENT; + } + + @RequestMapping(value = "/me/delete/{tokenUuid:.+}", method = RequestMethod.GET) + @PreAuthorize("isFullyAuthenticated()") + public String confirmDelete(ModelMap model, HttpServletRequest servletRequest, @PathVariable("tokenUuid") String tokenUuid, @RequestParam(value = "key", required = true) String key) throws NoSuchVerificationTokenException, TokenExpiredException, ServletException, UserException { + + emailVerificationService.confirmDeleteAccount(tokenUuid, key); + + servletRequest.logout(); + + return "redirect:/content/" + ContentService.DELETE_ACCOUNT_CONFIRMED; + } + + @RequestMapping(value = "/{uuid:.+}/update-roles", method = { RequestMethod.POST }) @PreAuthorize("hasRole('ADMINISTRATOR')") public String updateRoles(ModelMap model, @PathVariable("uuid") String uuid, @RequestParam("role") Set selectedRoles) { diff --git a/src/main/java/org/genesys2/server/servlet/controller/admin/UserProfileController.java b/src/main/java/org/genesys2/server/servlet/controller/admin/UserProfileController.java index b6272528457def934bc7b995f0483659a8ef26cf..7e5cdfa5bde25d7b6a655de41e51fb7516cb2e23 100644 --- a/src/main/java/org/genesys2/server/servlet/controller/admin/UserProfileController.java +++ b/src/main/java/org/genesys2/server/servlet/controller/admin/UserProfileController.java @@ -198,6 +198,30 @@ public class UserProfileController extends BaseController { return "redirect:" + URLBASE + user.getUuid(); } + @RequestMapping(value = "/{uuid:.+}/delete", method = RequestMethod.POST) + public String delete(ModelMap model, @PathVariable("uuid") String uuid) throws UserException { + final User user = userService.getUserByUuid(uuid); + + if (user==null) { + throw new ResourceNotFoundException(); + } + + // if (user.getAccountType() == AccountType.DELETED) { + // LOG.warn("Account already archived."); + // return "redirect:" + VIEWBASE; + // } + + if (! user.isAccountNonExpired()) { + LOG.warn("Account already expired."); + return "redirect:" + VIEWBASE; + } + + LOG.warn("Archiving user account {}", user.getEmail()); + userService.archiveUser(user); + + return "redirect:" + VIEWBASE; + } + @RequestMapping(value = "/{uuid:.+}/update-roles", method = { RequestMethod.POST }) public String updateRoles(ModelMap model, @PathVariable("uuid") String uuid, @RequestParam("role") Set selectedRoles) { final User user = userService.getUserByUuid(uuid); diff --git a/src/main/java/org/genesys2/spring/config/SecurityConfig.java b/src/main/java/org/genesys2/spring/config/SecurityConfig.java index ff0c5aac287e64ddfe809209a810439e86f76672..b1cc0841fd419ab9a6543fe50ab035983fe46ed3 100644 --- a/src/main/java/org/genesys2/spring/config/SecurityConfig.java +++ b/src/main/java/org/genesys2/spring/config/SecurityConfig.java @@ -128,13 +128,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(final HttpSecurity http) throws Exception { - + /*@formatter:off*/ http // No JSESSIONID in URL .sessionManagement().enableSessionUrlRewriting(false).sessionFixation().migrateSession() // Authorizations - .and().authorizeRequests().antMatchers("/admin/**", "/1/admin/**").hasRole("ADMINISTRATOR").antMatchers("/profile**", "/oauth/authorize", "/swagger-**").fullyAuthenticated() + .and().authorizeRequests() + // admin + .antMatchers("/admin/**", "/1/admin/**").hasRole("ADMINISTRATOR") + // require login + .antMatchers("/profile", "/profile/**", "/oauth/authorize", "/swagger-**").fullyAuthenticated() // access denied .and().exceptionHandling().accessDeniedPage("/access-denied") @@ -150,6 +154,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { // Login form .and().formLogin().permitAll().loginPage("/login").failureUrl("/login?error=1").loginProcessingUrl("/login-attempt").defaultSuccessUrl("/"); + /*@formatter:on*/ } @Override diff --git a/src/main/resources/default-content/account-delete-confirmed.json b/src/main/resources/default-content/account-delete-confirmed.json new file mode 100644 index 0000000000000000000000000000000000000000..9fd9711cace07ee97053ad688076f23df544ed5f --- /dev/null +++ b/src/main/resources/default-content/account-delete-confirmed.json @@ -0,0 +1,7 @@ +{ + "template": false, + "en": { + "title": "Removal of your user account is confirmed", + "body": "

We are processing your request to remove your Genesys user account!

\r\n

The user account is now disabled and you can no longer use it to log into Genesys. All personal information associated with the user account will be removed from Genesys within a grace period of 1 month.

" + } +} diff --git a/src/main/resources/default-content/account-delete-requested.json b/src/main/resources/default-content/account-delete-requested.json new file mode 100644 index 0000000000000000000000000000000000000000..81e1fe970fff1cf39fd7c7d30018c8913b36f452 --- /dev/null +++ b/src/main/resources/default-content/account-delete-requested.json @@ -0,0 +1,7 @@ +{ + "template": false, + "en": { + "title": "Confirm removal of your user account", + "body": "

A message was sent to your registered email address with a link to confirm your request.

\r\n

To remove your user account, please:

\r\n
  1. Remain logged into Genesys
  2. Check your Inbox and Spam folders for the confirmation message
  3. Open the link in the confirmation message to deactivate your user account and log you out of Genesys
  4. You are now no longer able to log into Genesys
  5. A message will be sent to your email address confirming your request to delete the user account and it will be deleted from Genesys after the 1 month grace period.
\r\n

\r\n

" + } +} diff --git a/src/main/resources/default-content/smtp-delete-account-inprogress.json b/src/main/resources/default-content/smtp-delete-account-inprogress.json new file mode 100644 index 0000000000000000000000000000000000000000..b3d4149bcf6856e2d6dcbd87f8fd5a0f673d2885 --- /dev/null +++ b/src/main/resources/default-content/smtp-delete-account-inprogress.json @@ -0,0 +1,7 @@ +{ + "template": true, + "en": { + "title": "Genesys user account removal is in progress", + "body": "

Dear {1},

\r\n

We are processing your request to remove your Genesys user account {2}. Your user account is now disabled and you can no longer use it to log into Genesys.

\r\n

All personal information will be removed from Genesys within a grace period of 1 month.

\r\n

 

\r\n

Sorry to see you go,
Genesys PGR team

" + } +} diff --git a/src/main/resources/default-content/smtp-delete-account.json b/src/main/resources/default-content/smtp-delete-account.json new file mode 100644 index 0000000000000000000000000000000000000000..cd791e62aa49937852fab071687b2017d7e9a417 --- /dev/null +++ b/src/main/resources/default-content/smtp-delete-account.json @@ -0,0 +1,7 @@ +{ + "template": true, + "en": { + "title": "Remove your Genesys user account", + "body": "

Dear {3},

\r\n

We have received your request to remove your Genesys user account {4} from {0} and are sending you this message to confirm the request.

\r\n

Not you?

\r\n

Simply ignore and delete this email message.

\r\n

Remove your Genesys user account

\r\n

We''re sorry to see you go! To remove your user account please click {0}/profile/me/delete/{1}?key={2}

\r\n

 

\r\n

Best regards,
Genesys PGR team

" + } +} diff --git a/src/main/resources/default-content/user-delete-account.json b/src/main/resources/default-content/user-delete-account.json new file mode 100644 index 0000000000000000000000000000000000000000..345c2f20dc72f0268999c3b5f50a11c1e951fa52 --- /dev/null +++ b/src/main/resources/default-content/user-delete-account.json @@ -0,0 +1,7 @@ +{ + "template": false, + "en": { + "title": "Delete user account", + "body": "

We're sorry to see you go. When your user account is deleted from Genesys any personal information associated with the account is removed from Genesys.

\r\n
  1. Genesys will send a confirmation email to your registered email address to validate account removal request
  2. The email message contains instructions and a hyperlink to deactivate your user account
  3. Opening the link in the confirmation message will immediatelly deactivate your account (please note that you must be logged into Genesys)
  4. Genesys will send you an email confirming that your user account has been deactivated and you can no longer use it to log into Genesys
  5. After a grace period of 1 month the account is deleted from Genesys
\r\n

You can always contact us at helpdesk@genesys-pgr.org to expedite the process.

\r\n

Are you sure?

\r\n

Click Delete to initiate the account removal process.

" + } +} \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/admin/users/index.jsp b/src/main/webapp/WEB-INF/jsp/admin/users/index.jsp index bf766c08c62e420cdc1c3e27dfd78a8ad01d6451..7cf4115862377bccdc6dbe9d69bcd571ff0ea49a 100644 --- a/src/main/webapp/WEB-INF/jsp/admin/users/index.jsp +++ b/src/main/webapp/WEB-INF/jsp/admin/users/index.jsp @@ -10,22 +10,23 @@ - - - + + + + + - + diff --git a/src/main/webapp/WEB-INF/jsp/admin/users/profile.jsp b/src/main/webapp/WEB-INF/jsp/admin/users/profile.jsp index 9722e8ed57f05cdfe65ee589fd8327c1dabf2b8a..36a793a902c251ea7dea4b4ac2c2cc4066214faa 100644 --- a/src/main/webapp/WEB-INF/jsp/admin/users/profile.jsp +++ b/src/main/webapp/WEB-INF/jsp/admin/users/profile.jsp @@ -22,6 +22,13 @@
+ +
+ +
+ +
+
@@ -34,6 +41,14 @@
+
+ +
+ + +
+
+
@@ -50,6 +65,7 @@ +
@@ -57,22 +73,30 @@
+

diff --git a/src/main/webapp/WEB-INF/jsp/content/index.jsp b/src/main/webapp/WEB-INF/jsp/content/index.jsp index e2db6e72231ad2bc632f663c03ffd9262739aa2c..c57c0d0bd6c8d9acef53b8d50c4a18678b8aeb4f 100644 --- a/src/main/webapp/WEB-INF/jsp/content/index.jsp +++ b/src/main/webapp/WEB-INF/jsp/content/index.jsp @@ -30,7 +30,7 @@
- + @@ -57,6 +57,7 @@ "> + ">JSON diff --git a/src/main/webapp/WEB-INF/jsp/user/delete.jsp b/src/main/webapp/WEB-INF/jsp/user/delete.jsp new file mode 100644 index 0000000000000000000000000000000000000000..18419299ae48b908a3e46a38ed27abc6665462f1 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/user/delete.jsp @@ -0,0 +1,24 @@ + + +<%@ include file="/WEB-INF/jsp/init.jsp" %> + + + +<c:out value="${info.title}" /> + + +

+ +
+
+
+ +
+ "/> + " /> + " class="btn btn-default"> + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/user/profile.jsp b/src/main/webapp/WEB-INF/jsp/user/profile.jsp index 6320353bb2dc0b0a86e903241a91cab52f016999..66efede19d6596aeb60347d68d0f3ae06a0ce3ca 100644 --- a/src/main/webapp/WEB-INF/jsp/user/profile.jsp +++ b/src/main/webapp/WEB-INF/jsp/user/profile.jsp @@ -13,6 +13,9 @@ " class="btn btn-default pull-right edit-btn"> + " class="btn btn-default pull-right edit-btn"> + +
diff --git a/src/main/webapp/WEB-INF/tags/paginate2.tag b/src/main/webapp/WEB-INF/tags/paginate2.tag index b8fb1213f53d1458ba659a590b64dfccb3d3d310..38b1dc5ef180c6882ebd65e7cb6dcc710d1e321d 100644 --- a/src/main/webapp/WEB-INF/tags/paginate2.tag +++ b/src/main/webapp/WEB-INF/tags/paginate2.tag @@ -9,6 +9,9 @@ <%-- This is the more civil
1Expires
- "> + "> SYSTEM DISABLED LOCKED