package org.akaza.openclinica.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.UUID;
import javax.servlet.ServletContext;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.akaza.openclinica.bean.core.NumericComparisonOperator;
import org.akaza.openclinica.bean.core.Role;
import org.akaza.openclinica.bean.core.Status;
import org.akaza.openclinica.bean.core.TermType;
import org.akaza.openclinica.bean.core.UserType;
import org.akaza.openclinica.bean.login.StudyUserRoleBean;
import org.akaza.openclinica.bean.login.UserAccountBean;
import org.akaza.openclinica.bean.login.UserDTO;
import org.akaza.openclinica.bean.managestudy.StudyBean;
import org.akaza.openclinica.bean.managestudy.StudySubjectBean;
import org.akaza.openclinica.control.SpringServletAccess;
import org.akaza.openclinica.control.form.Validator;
import org.akaza.openclinica.core.SecurityManager;
import org.akaza.openclinica.dao.hibernate.AuthoritiesDao;
import org.akaza.openclinica.dao.login.UserAccountDAO;
import org.akaza.openclinica.dao.managestudy.StudyDAO;
import org.akaza.openclinica.dao.managestudy.StudySubjectDAO;
import org.akaza.openclinica.domain.user.AuthoritiesBean;
import org.akaza.openclinica.i18n.core.LocaleResolver;
import org.akaza.openclinica.i18n.util.ResourceBundleProvider;
import org.akaza.openclinica.service.pmanage.ParticipantPortalRegistrar;
import org.akaza.openclinica.view.Page;
import org.apache.commons.dbcp.BasicDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
@RequestMapping(value = "/auth/api/v1")
@ResponseStatus(value = org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
public class UserAccountController {
@Autowired
@Qualifier("dataSource")
private BasicDataSource dataSource;
@Autowired
ServletContext context;
@Autowired
AuthoritiesDao authoritiesDao;
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
UserAccountDAO udao;
StudyDAO sdao;
StudySubjectDAO ssdao;
UserAccountBean uBean;
/**
* @api {post} /pages/auth/api/v1/createuseraccount Create a user account
* @apiName createOrUpdateAccount2
* @apiPermission admin
* @apiVersion 3.8.0
* @apiParam {String} username UserName
* @apiParam {String} fName First Name
* @apiParam {String} lName Last Name
* @apiParam {String} institution Institution
* @apiParam {String} email Email Address
* @apiParam {String} study_name Study Name
* @apiParam {String} role_name Role Name
* @apiParam {String} user_type User Type
* @apiParam {String} authorize_soap Authorize Soap
*
* @apiGroup User Account
* @apiDescription Creates a user account
* @apiParamExample {json} Request-Example:
* {
* "username": "testingUser",
* "fName": "Jimmy",
* "lName": "Sander",
* "institution": "OC",
* "email": "abcde@yahoo.com",
* "study_name": "Baseline Study 101",
* "role_name": "Data Manager",
* "user_type": "user",
* "authorize_soap":"false"
* }
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 400 Bad Request
* {
* }
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "lastName": "Sander",
* "username": "testingUser",
* "firstName": "Jimmy",
* "password": "rgluVsO0",
* "apiKey": "5f462a16b3b04b1b9747262968bd5d2f"
* }
*/
@RequestMapping(value = "/createuseraccount", method = RequestMethod.POST)
public ResponseEntity<HashMap> createOrUpdateAccount(HttpServletRequest request, @RequestBody HashMap<String, String> map) throws Exception {
logger.info("I'm in createUserAccount");
System.out.println("I'm in createUserAccount");
uBean = null;
String username = map.get("username");
String fName = map.get("fName");
String lName = map.get("lName");
String institution = map.get("institution");
String email = map.get("email");
String studyName = map.get("study_name");
String roleName = map.get("role_name");
String userType = map.get("user_type");
String authorizeSoap = map.get("authorize_soap"); // true or false
request.setAttribute("username", username);
request.setAttribute("fName", fName);
request.setAttribute("lName", lName);
request.setAttribute("institution", institution);
request.setAttribute("email", email);
request.setAttribute("study_name", studyName);
request.setAttribute("role_name", roleName);
// UserAccountBean ownerUserAccount = getUserAccountByApiKey(apiKey);
UserAccountBean ownerUserAccount = (UserAccountBean) request.getSession().getAttribute("userBean");
if (!ownerUserAccount.isActive() && (!ownerUserAccount.isTechAdmin() || !ownerUserAccount.isSysAdmin())) {
logger.info("The Owner User Account is not Valid Account or Does not have Admin user type");
System.out.println("The Owner User Account is not Valid Account or Does not have Admin user type");
return new ResponseEntity<HashMap>(new HashMap(), org.springframework.http.HttpStatus.BAD_REQUEST);
}
// generate password
String password = ""; // generate
String passwordHash = UserAccountBean.LDAP_PASSWORD;
SecurityManager secm = (SecurityManager) SpringServletAccess.getApplicationContext(context).getBean("securityManager");
password = secm.genPassword();
passwordHash = secm.encrytPassword(password, null);
// Validate Entry Fields
request.getSession().setAttribute(LocaleResolver.getLocaleSessionAttributeName(), new Locale("en_US"));
Validator v = new Validator(request);
addValidationToFields(v, username);
HashMap errors = v.validate();
if (!errors.isEmpty()) {
logger.info("Validation Error: " + errors.toString());
System.out.println("Validation Error: " + errors.toString());
return new ResponseEntity<HashMap>(new HashMap(), org.springframework.http.HttpStatus.BAD_REQUEST);
}
StudyBean study = getStudyByName(studyName);
if (!study.isActive()) {
logger.info("The Study Name is not Valid");
System.out.println("The Study Name is not Valid");
return new ResponseEntity<HashMap>(new HashMap(), org.springframework.http.HttpStatus.BAD_REQUEST);
}
// Role
ResourceBundle resterm = org.akaza.openclinica.i18n.util.ResourceBundleProvider.getTermsBundle();
Map<Integer, String> roleMap = buildRoleMap(study, resterm);
boolean found = false;
Role role = null;
for (Map.Entry<Integer, String> entry : roleMap.entrySet()) {
if (roleName.equalsIgnoreCase(entry.getValue())) {
Integer key = entry.getKey();
role = Role.get(key);
found = true;
break;
}
}
if (!found) {
logger.info("The Role is not a Valid Role for the Study or Site");
System.out.println("The Role is not a Valid Role for the Study or Site");
return new ResponseEntity<HashMap>(new HashMap(), org.springframework.http.HttpStatus.BAD_REQUEST);
}
// User Types
found = false;
UserType uType = null;
ArrayList<UserType> types = UserType.toArrayList();
types.remove(UserType.INVALID);
for (UserType type : types) {
if (userType.equalsIgnoreCase(type.getName())) {
uType = UserType.get(type.getId());
found = true;
break;
}
}
if (!found) {
logger.info("The Type is not a Valid User Type");
System.out.println("The Type is not a Valid User Type");
return new ResponseEntity<HashMap>(new HashMap(), org.springframework.http.HttpStatus.BAD_REQUEST);
}
// build UserName
uBean = buildUserAccount(username, fName, lName, password, institution, study, ownerUserAccount, email, passwordHash, Boolean.valueOf(authorizeSoap), role, uType);
HashMap<String, Object> userDTO = null;
UserAccountBean uaBean = getUserAccount(uBean.getName());
if (!uaBean.isActive()) {
createUserAccount(uBean);
uBean.setUpdater(uBean.getOwner());
updateUserAccount(uBean);
logger.info("***New User Account is created***");
System.out.println("***New User Account is created***");
uBean.setPasswd(password);
userDTO = new HashMap<String, Object>();
userDTO.put("username", uBean.getName());
userDTO.put("password", uBean.getPasswd());
userDTO.put("firstName", uBean.getFirstName());
userDTO.put("lastName", uBean.getLastName());
userDTO.put("apiKey", uBean.getApiKey());
}
return new ResponseEntity<HashMap>(userDTO, org.springframework.http.HttpStatus.OK);
}
private UserAccountBean buildUserAccount(String username, String fName, String lName, String password, String institution, StudyBean study, UserAccountBean ownerUserAccount, String email,
String passwordHash, Boolean authorizeSoap, Role roleName, UserType userType) throws Exception {
UserAccountBean createdUserAccountBean = new UserAccountBean();
createdUserAccountBean.setName(username);
createdUserAccountBean.setFirstName(fName);
createdUserAccountBean.setLastName(lName);
createdUserAccountBean.setEmail(username);
createdUserAccountBean.setInstitutionalAffiliation(institution);
createdUserAccountBean.setLastVisitDate(null);
createdUserAccountBean.setActiveStudyId(study.getId());
createdUserAccountBean.setPasswdTimestamp(null);
createdUserAccountBean.setPasswdChallengeQuestion("");
createdUserAccountBean.setPasswdChallengeAnswer("");
createdUserAccountBean.setOwner(ownerUserAccount);
createdUserAccountBean.setRunWebservices(false);
createdUserAccountBean.setPhone("");
createdUserAccountBean.setAccessCode("");
createdUserAccountBean.setPasswd(password);
createdUserAccountBean.setEmail(email);
createdUserAccountBean.setEnableApiKey(true);
createdUserAccountBean.setPasswd(passwordHash);
createdUserAccountBean.setRunWebservices(authorizeSoap);
String apiKey = null;
do {
apiKey = getRandom32ChApiKey();
} while (isApiKeyExist(apiKey));
createdUserAccountBean.setApiKey(apiKey);
createdUserAccountBean = addActiveStudyRole(createdUserAccountBean, study.getId(), roleName, ownerUserAccount);
createdUserAccountBean.addUserType(userType);
authoritiesDao.saveOrUpdate(new AuthoritiesBean(createdUserAccountBean.getName()));
return createdUserAccountBean;
}
private void createUserAccount(UserAccountBean userAccountBean) {
udao = new UserAccountDAO(dataSource);
udao.create(userAccountBean);
}
private StudyBean getParentStudy(String studyOid) {
StudyBean study = getStudy(studyOid);
if (study.getParentStudyId() == 0) {
return study;
} else {
StudyBean parentStudy = (StudyBean) sdao.findByPK(study.getParentStudyId());
return parentStudy;
}
}
private StudyBean getParentStudy(Integer studyId) {
StudyBean study = getStudy(studyId);
if (study.getParentStudyId() == 0) {
return study;
} else {
StudyBean parentStudy = (StudyBean) sdao.findByPK(study.getParentStudyId());
return parentStudy;
}
}
private StudyBean getStudyByName(String name) {
sdao = new StudyDAO(dataSource);
StudyBean studyBean = (StudyBean) sdao.findByName(name);
return studyBean;
}
private StudyBean getStudy(String oid) {
sdao = new StudyDAO(dataSource);
StudyBean studyBean = (StudyBean) sdao.findByOid(oid);
return studyBean;
}
private StudyBean getStudy(Integer id) {
sdao = new StudyDAO(dataSource);
StudyBean studyBean = (StudyBean) sdao.findByPK(id);
return studyBean;
}
private UserAccountBean addActiveStudyRole(UserAccountBean createdUserAccountBean, int studyId, Role r, UserAccountBean ownerUserAccount) {
StudyUserRoleBean studyUserRole = new StudyUserRoleBean();
studyUserRole.setStudyId(studyId);
studyUserRole.setRoleName(r.getName());
studyUserRole.setStatus(Status.AVAILABLE);
studyUserRole.setOwner(ownerUserAccount);
createdUserAccountBean.addRole(studyUserRole);
createdUserAccountBean.setAccountNonLocked(false);
return createdUserAccountBean;
}
private ArrayList<UserAccountBean> getUserAccountByStudy(String userName, ArrayList allStudies) {
udao = new UserAccountDAO(dataSource);
ArrayList<UserAccountBean> userAccountBeans = udao.findStudyByUser(userName, allStudies);
return userAccountBeans;
}
private UserAccountBean getUserAccount(String userName) {
udao = new UserAccountDAO(dataSource);
UserAccountBean userAccountBean = (UserAccountBean) udao.findByUserName(userName);
return userAccountBean;
}
private UserAccountBean getUserAccountByApiKey(String apiKey) {
udao = new UserAccountDAO(dataSource);
UserAccountBean userAccountBean = (UserAccountBean) udao.findByApiKey(apiKey);
return userAccountBean;
}
private void updateUserAccount(UserAccountBean userAccountBean) {
udao.update(userAccountBean);
}
private ArrayList getRoles() {
ArrayList roles = Role.toArrayList();
roles.remove(Role.ADMIN);
return roles;
}
public Boolean isApiKeyExist(String uuid) {
UserAccountDAO udao = new UserAccountDAO(dataSource);
UserAccountBean uBean = (UserAccountBean) udao.findByApiKey(uuid);
if (uBean == null || !uBean.isActive()) {
return false;
} else {
return true;
}
}
public String getRandom32ChApiKey() {
String uuid = UUID.randomUUID().toString();
return uuid.replaceAll("-", "");
}
protected UserDetails getUserDetails() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
return (UserDetails) principal;
} else {
return null;
}
}
public void addValidationToFields(Validator v, String username) {
v.addValidation("username", Validator.NO_BLANKS);
v.addValidation("username", Validator.LENGTH_NUMERIC_COMPARISON, NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 64);
if (!username.equals("root"))
v.addValidation("username", Validator.IS_A_USERNAME);
v.addValidation("username", Validator.USERNAME_UNIQUE, udao);
v.addValidation("fName", Validator.NO_BLANKS);
v.addValidation("fName", Validator.LENGTH_NUMERIC_COMPARISON, NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 50);
v.addValidation("lName", Validator.LENGTH_NUMERIC_COMPARISON, NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 50);
v.addValidation("email", Validator.NO_BLANKS);
v.addValidation("email", Validator.LENGTH_NUMERIC_COMPARISON, NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 120);
v.addValidation("email", Validator.IS_A_EMAIL);
v.addValidation("institution", Validator.NO_BLANKS);
v.addValidation("institution", Validator.LENGTH_NUMERIC_COMPARISON, NumericComparisonOperator.LESS_THAN_OR_EQUAL_TO, 255);
// v.addValidation("study_name", Validator.ENTITY_EXISTS, sdao);
// v.addValidation("role_name", Validator.IS_VALID_TERM, TermType.ROLE);
}
public Map buildRoleMap(StudyBean study, ResourceBundle resterm) {
Map roleMap = new LinkedHashMap();
if (study.getParentStudyId() > 0) {
for (Iterator it = getRoles().iterator(); it.hasNext();) {
Role role = (Role) it.next();
switch (role.getId()) {
// case 2: roleMap.put(role.getId(), resterm.getString("site_Study_Coordinator").trim());
// break;
// case 3: roleMap.put(role.getId(), resterm.getString("site_Study_Director").trim());
// break;
case 4:
roleMap.put(role.getId(), resterm.getString("site_investigator").trim());
break;
case 5:
roleMap.put(role.getId(), resterm.getString("site_Data_Entry_Person").trim());
break;
case 6:
roleMap.put(role.getId(), resterm.getString("site_monitor").trim());
break;
case 7:
roleMap.put(role.getId(), resterm.getString("site_Data_Entry_Person2").trim());
break;
default:
// logger.info("No role matched when setting role description");
}
}
} else {
for (Iterator it = getRoles().iterator(); it.hasNext();) {
Role role = (Role) it.next();
switch (role.getId()) {
case 2:
roleMap.put(role.getId(), resterm.getString("Study_Coordinator").trim());
break;
case 3:
roleMap.put(role.getId(), resterm.getString("Study_Director").trim());
break;
case 4:
roleMap.put(role.getId(), resterm.getString("Investigator").trim());
break;
case 5:
roleMap.put(role.getId(), resterm.getString("Data_Entry_Person").trim());
break;
case 6:
roleMap.put(role.getId(), resterm.getString("Monitor").trim());
break;
default:
// logger.info("No role matched when setting role description");
}
}
}
return roleMap;
}
}