Commit bc232ba0 authored by Maxym Borodenko's avatar Maxym Borodenko Committed by Matija Obreza

FTP password

Signed-off-by: Matija Obreza's avatarMatija Obreza <matija.obreza@croptrust.org>
parent 73c33a6a
......@@ -19,9 +19,11 @@ package org.genesys2.server.model.impl;
import java.beans.Transient;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.genesys.blocks.security.model.BasicUser;
......@@ -36,6 +38,18 @@ public class User extends BasicUser<UserRole> {
private static final long serialVersionUID = 4564013753931115445L;
@JsonIgnore
@Column(length = 60)
private String ftpPassword;
public String getFtpPassword() {
return ftpPassword;
}
public void setFtpPassword(final String ftpPassword) {
this.ftpPassword = ftpPassword;
}
@Override
public String toString() {
return "User id=" + getId() + " email=" + getEmail();
......
......@@ -75,4 +75,6 @@ public interface UserService extends BasicUserService<UserRole, User> {
User setAccountType(User user, AccountType accountType);
void setFtpPassword(User user, String ftpPassword) throws PasswordPolicyException;
}
......@@ -31,6 +31,7 @@ import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser.AccountType;
import org.genesys.blocks.security.service.PasswordPolicy;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys.blocks.security.service.impl.BasicUserServiceImpl;
import org.genesys2.server.model.UserRole;
......@@ -71,6 +72,9 @@ public class UserServiceImpl extends BasicUserServiceImpl<UserRole, User> implem
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordPolicy passwordPolicy;
private final List<UserRole> availableRoles = ListUtils.unmodifiableList(Arrays.asList(UserRole.values()));
private EmailValidator emailValidator = EmailValidator.getInstance();
......@@ -406,4 +410,16 @@ public class UserServiceImpl extends BasicUserServiceImpl<UserRole, User> implem
return userRepository.save(u);
}
/**
* Set FTP application password for the user.
*/
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') || principal.user.id == #user.id")
public void setFtpPassword(final User user, final String ftpPassword) throws PasswordPolicyException {
passwordPolicy.assureGoodPassword(ftpPassword);
user.setFtpPassword(passwordEncoder.encode(ftpPassword));
userRepository.save(user);
}
}
......@@ -17,6 +17,7 @@
package org.genesys2.server.servlet.controller;
import java.io.IOException;
import java.util.Random;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
......@@ -34,11 +35,15 @@ import org.genesys2.server.service.TokenVerificationService.NoSuchVerificationTo
import org.genesys2.server.service.TokenVerificationService.TokenExpiredException;
import org.genesys2.server.service.UserService;
import org.genesys2.spring.ResourceNotFoundException;
import org.genesys2.util.RandomPasswordUtil;
import org.genesys2.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Controller;
......@@ -47,6 +52,7 @@ 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;
@Controller
......@@ -92,6 +98,29 @@ public class UserProfileController extends BaseController {
return "redirect:/profile/" + uuid;
}
@RequestMapping(value = "/{uuid:.+}/generate-ftp-password", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('ADMINISTRATOR', 'VETTEDUSER')")
@ResponseBody
public ResponseEntity<?> generateFtpPassword(@PathVariable("uuid") String uuid) {
String generatedPassword = RandomPasswordUtil.generatePassword(new Random(), 15);
final User user = userService.getUserByUuid(uuid);
if (user == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
final Object result = new Object() {
@SuppressWarnings("unused")
public String password = generatedPassword;
};
try {
userService.setFtpPassword(user, generatedPassword);
return new ResponseEntity<>(result, HttpStatus.OK);
} catch (PasswordPolicyException e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@RequestMapping("/{uuid:.+}")
@PreAuthorize("isAuthenticated()")
public String someProfile(ModelMap model, @PathVariable("uuid") String uuid) {
......
......@@ -41,5 +41,4 @@ public class ApplicationConfig {
public BrAPIService brapiService() {
return new BrAPIServiceImpl();
}
}
/**
* Copyright 2017 Global Crop Diversity Trust
*
* Licensed 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.
**/
package org.genesys2.util;
import java.util.Random;
/**
* @author Maxym Borodenko
*/
public class RandomPasswordUtil {
private static final String symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$&@?~!%#";
/**
* This method generates a random password that consists of at least one special character, one number,
* one lowercase letter and one uppercase letter
*
* @param random
* @param length the password length that should be generated
* @return string with generated password
* @throws IllegalArgumentException if the 'length' parameter is lower than 4 characters
*/
public static String generatePassword(final Random random, final int length) {
if (length < 4) {
throw new IllegalArgumentException("Password must be at least 4 characters");
}
while (true) {
char[] password = new char[length];
boolean hasUpper = false, hasLower = false, hasDigit = false, hasSpecial = false;
for (int i = 0; i < password.length; i++) {
char ch = symbols.charAt(random.nextInt(symbols.length()));
if (Character.isUpperCase(ch))
hasUpper = true;
else if (Character.isLowerCase(ch))
hasLower = true;
else if (Character.isDigit(ch))
hasDigit = true;
else
hasSpecial = true;
password[i] = ch;
}
if (hasUpper && hasLower && hasDigit && hasSpecial) {
return new String(password);
}
}
}
}
......@@ -135,6 +135,7 @@ user.pulldown.heading={0}
user.create-new-account=Create an account
user.full-name=Full Name
user.email=E-mail Address
user.generate-ftp-password=Generate FTP password
user.account-status=Account Status
user.account-disabled=Account disabled
user.account-locked-until=Account locked until
......@@ -143,6 +144,7 @@ user.login-type=Login Type
userprofile.page.title=User profile
userprofile.page.intro=As a community, Genesys relies on its users to be successful. Whether you’re an individual researcher or represent a larger institution, you can update your profile here to show your interests and the data in your collection.
userprofile.update.title=Update your profile
userprofile.page.ftp-credentials=Your FTP credentials are:
user.page.list.title=Registered user accounts
......
......@@ -217,3 +217,14 @@ databaseChangeLog:
- column:
name: doi
type: varchar(255)
- changeSet:
id: 1505830865186-1
author: maxymborodenko (generated)
changes:
- addColumn:
tableName: user
columns:
- column:
name: ftpPassword
type: varchar(60)
\ No newline at end of file
......@@ -4,7 +4,7 @@
<html>
<head>
<title><spring:message code="userprofile.page.title" /></title>
<title><spring:message code="userprofile.page.title" /></title>
</head>
<body>
<cms:informative-h1 title="userprofile.page.title" fancy="true" info="userprofile.page.intro" />
......@@ -15,7 +15,7 @@
</a>
</security:authorize>
<div class="form-horizontal">
<div class="form-horizontal" id="user-profile-info">
<div class="form-group">
<label for="password" class="col-lg-2 control-label"><spring:message code="user.full-name" /></label>
<div class="col-lg-5 form-control-static"><c:out value="${user.fullName}" /></div>
......@@ -54,6 +54,23 @@
</security:authorize>
<security:authorize access="hasAnyRole('ADMINISTRATOR', 'VETTEDUSER')">
<c:if test="${user.ftpPassword ne null}">
<div class="form-group" id="ftp-credentials">
<label class="col-lg-2 control-label"><spring:message code="userprofile.page.ftp-credentials" /></label>
<div class="col-lg-5 form-control-static">
<div>
<label for="ftp-username"><spring:message code="login.username" /></label>
<span id="ftp-username"><c:out value="${user.email}" /></span>
</div>
<div>
<label for="ftp-password"><spring:message code="login.password" /></label>
<span id="ftp-password">*</span>
</div>
</div>
</div>
</c:if>
</security:authorize>
</div>
......@@ -77,7 +94,7 @@
</security:authorize>
<security:authorize access="hasRole('ADMINISTRATOR') || principal.id == #user.id">
<c:if test="${not user.hasRole('VALIDATEDUSER')}">
<a href="<c:url value="/profile/${user.uuid}/send"/>" class="btn btn-default"/>Send validation email</a>
<a href="<c:url value="/profile/${user.uuid}/send"/>" class="btn btn-default">Send validation email</a>
</c:if>
</security:authorize>
<security:authorize access="hasAnyRole('VETTEDUSER','ADMINISTRATOR')">
......@@ -85,12 +102,15 @@
</security:authorize>
<security:authorize access="hasRole('ADMINISTRATOR')">
<c:if test="${not user.hasRole('VETTEDUSER')}">
<a href="<c:url value="/profile/${user.uuid}/vetted-user"/> "class="btn btn-default"/>Vetted user</a>
<a href="<c:url value="/profile/${user.uuid}/vetted-user"/> " class="btn btn-default">Vetted user</a>
</c:if>
<security:authorize access="isAuthenticated()">
<a href="#" data-toggle="modal" data-target="#myModal" class="btn btn-default get_widget" id="get_widget">Get Widget</a>
</security:authorize>
</security:authorize>
<security:authorize access="hasAnyRole('ADMINISTRATOR', 'VETTEDUSER')">
<input type="button" id="generate-ftp-password-btn" value="<spring:message code="user.generate-ftp-password" />" class="btn btn-default" />
</security:authorize>
</div>
<!-- Modal -->
......@@ -134,6 +154,45 @@
}}, false);
});
</security:authorize>
<security:authorize access="hasAnyRole('ADMINISTRATOR', 'VETTEDUSER')">
$('body').on('click', '#generate-ftp-password-btn', function () {
$.ajax({
type: 'POST',
dataType: 'json',
url: '<c:url value="/profile/${user.uuid}/generate-ftp-password" />',
contentType: 'application/json; charset=utf-8',
beforeSend: function(xhrObj){
xhrObj.setRequestHeader("Accept", "application/json");
},
success: function (respObject) {
if ($('#ftp-credentials').length) {
$('#ftp-password').text(' ' + respObject.password);
} else {
renderUserFtpCredentials(respObject.password);
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
console.log(errorThrown);
}
});
});
function renderUserFtpCredentials(password) {
$('#user-profile-info')
.append($('<div id="ftp-credentials" />').addClass('form-group')
.append($('<label/>').addClass('col-lg-2 control-label').append('<spring:message code="userprofile.page.ftp-credentials" />'))
.append($('<div />').addClass('col-lg-5 form-control-static')
.append($('<div />')
.append($('<label for="ftp-username" />').append('<spring:message code="login.username" />'))
.append($('<span id="ftp-username" />').append('<c:out value="${user.email}" />')))
.append($('<div />')
.append($('<label for="ftp-password" />').append('<spring:message code="login.password" />'))
.append($('<span id="ftp-password" />').append(' ' + password)))));
}
</security:authorize>
});
</script>
</security:authorize>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment