package com.evolveum.midpoint.web.page.admin.home;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.web.component.prism.ObjectWrapperFactory;
import com.evolveum.midpoint.web.page.self.PageSelfDashboard;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.IModel;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.RetrieveOption;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.MiscSchemaUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.application.PageDescriptor;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.AjaxSubmitButton;
import com.evolveum.midpoint.web.component.prism.ContainerStatus;
import com.evolveum.midpoint.web.component.prism.ObjectWrapper;
import com.evolveum.midpoint.web.page.admin.home.component.MyPasswordQuestionsPanel;
import com.evolveum.midpoint.web.page.admin.home.dto.PasswordQuestionsDto;
import com.evolveum.midpoint.web.page.admin.home.dto.SecurityQuestionAnswerDTO;
import com.evolveum.midpoint.web.security.SecurityUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionAnswerType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionsCredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
@PageDescriptor(url = "/PasswordQuestions")
public class PageMyPasswordQuestions extends PageAdminHome {
private static final Trace LOGGER = TraceManager.getTrace(PageMyPasswordQuestions.class);
private static final String DOT_CLASS = PageMyPasswordQuestions.class.getName() + ".";
private static final String OPERATION_LOAD_USER = DOT_CLASS + "loaduser";
private static final String OPERATION_LOAD_QUESTION_POLICY = DOT_CLASS + "LOAD Question Policy";
private String ID_PASSWORD_QUESTIONS_PANEL = "pwdQuestionsPanel";
private static final String OPERATION_SAVE_QUESTIONS="Save Security Questions";
private static final String ID_MAIN_FORM = "mainForm";
private static final String ID_BACK = "back";
private static final String ID_SAVE = "save";
private LoadableModel<ObjectWrapper> userModel;
private List<MyPasswordQuestionsPanel> pqPanels;
private IModel<PasswordQuestionsDto> model;
private List<SecurityQuestionDefinitionType> policyQuestionList;
private MyPasswordQuestionsPanel pwPanel;
int questionNumber;
public PageMyPasswordQuestions() {
model = new LoadableModel<PasswordQuestionsDto>(false) {
private static final long serialVersionUID = 1L;
@Override
protected PasswordQuestionsDto load() {
return loadPageModel();
}
};
initLayout();
}
public PageMyPasswordQuestions(IModel<PasswordQuestionsDto> model){
this.model = model;
initLayout();
}
public PageMyPasswordQuestions(final PrismObject<UserType> userToEdit) {
userModel = new LoadableModel<ObjectWrapper>(false) {
@Override
protected ObjectWrapper load() {
return loadUserWrapper(userToEdit);
}
};
initLayout();
}
private PasswordQuestionsDto loadPageModel() {
LOGGER.debug("Loading user for Security Question Page.");
PasswordQuestionsDto dto =new PasswordQuestionsDto();
OperationResult result = new OperationResult(OPERATION_LOAD_USER);
try{
String userOid = SecurityUtils.getPrincipalUser().getOid();
Task task = createSimpleTask(OPERATION_LOAD_USER);
OperationResult subResult = result.createSubresult(OPERATION_LOAD_USER);
PrismObject<UserType> user = getModelService().getObject(UserType.class, userOid, null, task, subResult);
dto.setSecurityAnswers(createUsersSecurityQuestionsList(user));
subResult.recordSuccessIfUnknown();
}
catch (Exception ex) {
LoggingUtils.logExceptionOnDebugLevel(LOGGER, "Couldn't get user Questions, Probably not set yet", ex);
} finally {
result.recomputeStatus();
}
return dto;
}
public List<SecurityQuestionAnswerDTO> createUsersSecurityQuestionsList(PrismObject<UserType> user){
LOGGER.debug("Security Questions Loading for user: "+ user.getOid());
if (user.asObjectable().getCredentials() != null && user.asObjectable().getCredentials().getSecurityQuestions() != null) {
List<SecurityQuestionAnswerType> secQuestAnsList = user.asObjectable().getCredentials().getSecurityQuestions().getQuestionAnswer();
if (secQuestAnsList != null) {
LOGGER.debug("User SecurityQuestion ANswer List is Not null");
List<SecurityQuestionAnswerDTO> secQuestAnswListDTO = new ArrayList<SecurityQuestionAnswerDTO>();
for (Iterator iterator = secQuestAnsList.iterator(); iterator
.hasNext(); ) {
SecurityQuestionAnswerType securityQuestionAnswerType = (SecurityQuestionAnswerType) iterator
.next();
Protector protector = getPrismContext().getDefaultProtector();
String decoded = "";
if (securityQuestionAnswerType.getQuestionAnswer().getEncryptedDataType() != null) {
try {
decoded = protector.decryptString(securityQuestionAnswerType.getQuestionAnswer());
} catch (EncryptionException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't decrypt user answer", e);
}
}
//LOGGER.debug("SecAnswerIdentifier:"+securityQuestionAnswerType.getQuestionIdentifier());
secQuestAnswListDTO.add(new SecurityQuestionAnswerDTO(securityQuestionAnswerType.getQuestionIdentifier(), decoded));
}
return secQuestAnswListDTO;
}
}
return null;
}
public void initLayout(){
Form mainForm = new Form(ID_MAIN_FORM);
//question panel list
pqPanels = new ArrayList<MyPasswordQuestionsPanel>();
OperationResult result = new OperationResult(OPERATION_LOAD_QUESTION_POLICY);
try{
Task task = getPageBase().createSimpleTask(OPERATION_LOAD_QUESTION_POLICY);
OperationResult subResult = result.createSubresult(OPERATION_LOAD_QUESTION_POLICY);
try{
//PrismObject<SystemConfigurationType> config = getPageBase().getModelService().getObject(
// SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), null,
//task, result);
CredentialsPolicyType credPolicy=getModelInteractionService().getCredentialsPolicy(null, null, result);
// PrismObject<SecurityPolicyType> securityPolicy = getModelService().getObject(SecurityPolicyType.class,config.asObjectable().getGlobalSecurityPolicyRef().getOid(), null, task, subResult);
//Global Policy set question numbers
if (credPolicy != null && credPolicy.getSecurityQuestions() != null) {
questionNumber = credPolicy.getSecurityQuestions().getQuestionNumber();
// Actual Policy Question List
policyQuestionList = credPolicy.getSecurityQuestions().getQuestion();
} else {
questionNumber = 0;
policyQuestionList = new ArrayList<SecurityQuestionDefinitionType>();
}
}catch(Exception ex){
ex.printStackTrace();
/* List<SecurityQuestionAnswerDTO> userQuestionList= model.getObject().getSecurityAnswers();
int panelNumber=0;
PrismObject<UserType> user = null;
Collection options = SelectorOptions.createCollection(UserType.F_CREDENTIALS,
GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE));
Task taskTwo = createSimpleTask("LOAD USER WRAPPER");
user = getModelService().getObject(UserType.class, SecurityUtils.getPrincipalUser().getOid(), options, taskTwo, result);
OperationResult parentResult = new OperationResult(OPERATION_LOAD_QUESTION_POLICY);
questionNumber = getModelInteractionService().getCredentialsPolicy(user, parentResult).getSecurityQuestions().getQuestionNumber();
policyQuestionList=getModelInteractionService().getCredentialsPolicy(user, parentResult).getSecurityQuestions().getQuestion();
if(userQuestionList==null){
executeAddingQuestions(questionNumber, 0, policyQuestionList);
LOGGER.info(getModelInteractionService().getCredentialsPolicy(user, parentResult).getSecurityQuestions().getQuestionNumber().toString());
}else{
for(int userQuestint=0;userQuestint<userQuestionList.size();userQuestint++){
SecurityQuestionAnswerDTO answerDTO= checkIfQuestionisValid(userQuestionList.get(userQuestint), policyQuestionList);
if (userQuestionList.get(userQuestint)!=null){
LOGGER.debug("Questitself"+userQuestionList.get(userQuestint).getQuestionItself());
MyPasswordQuestionsPanel panel=new MyPasswordQuestionsPanel(ID_PASSWORD_QUESTIONS_PANEL+ panelNumber,userQuestionList.get(userQuestint));
pqPanels.add(panel);
panelNumber++;
}
}
//TODO same questions check should be implemented
}
add(mainForm);
mainForm.add(getPanels(pqPanels));
initButtons(mainForm);
return;
*/
}
/*User's Pre-Set Question List*/
List<SecurityQuestionAnswerDTO> userQuestionList= model.getObject().getSecurityAnswers();
/* check if user's set number of
* questions matches the policy or not*/
//Case that policy have more than users's number of numbers
if((userQuestionList==null) || (questionNumber>userQuestionList.size())){
if(userQuestionList==null){
executeAddingQuestions(questionNumber, 0, policyQuestionList);
//TODO same questions check should be implemented
}else{
executePasswordQuestionsAndAnswers(userQuestionList, policyQuestionList, userQuestionList.size());
//QUESTION NUMBER BIGGER THAN QUESTION LIST
//rest of the questions
int difference=questionNumber-userQuestionList.size();
executeAddingQuestions(difference, userQuestionList.size(), policyQuestionList);
}
}else if(questionNumber==userQuestionList.size()){
//QUESTION NUMBER EQUALS TO QUESTION LIST
executePasswordQuestionsAndAnswers(userQuestionList, policyQuestionList, 0);
//TODO PART2: Case that policy have smaller than users's number of numbers
}else if(questionNumber < userQuestionList.size()){
//QUESTION NUMBER SMALLER THAN QUESTION LIST
executePasswordQuestionsAndAnswers(userQuestionList, policyQuestionList, 0);
//this part will be using at remove operation in the future
/* int diff = userQuestionList.size()-questionNumber;
for(Iterator iterator = userQuestionList.iterator(); iterator.hasNext();){
SecurityQuestionAnswerDTO element = (SecurityQuestionAnswerDTO)iterator.next();
for(int i=0; i<diff;i++){
if(element == userQuestionList.get(questionNumber+i)){
try{
//LOGGER.info("REMOVE");
iterator.remove();
} catch (UnsupportedOperationException uoe) {
LOGGER.info(uoe.getStackTrace().toString());
}
}
}
}*/
}
} catch (Exception ex) {
result.recordFatalError("Couldn't load system configuration.", ex);
}
add(mainForm);
mainForm.add(getPanels(pqPanels));
initButtons(mainForm);
}
/**
* method for adding questions to user credentials
* @author oguzhan
* @param questionNumber
* @param panelNumber
* @param policyQuestionList
*/
public void executeAddingQuestions(int questionNumber,int panelNumber,List<SecurityQuestionDefinitionType> policyQuestionList){
LOGGER.debug("executeAddingQuestions");
for(int i=0;i<questionNumber;i++){
//LOGGER.info("\n\n Adding panel element");
SecurityQuestionAnswerDTO a=new SecurityQuestionAnswerDTO(policyQuestionList.get(panelNumber).getIdentifier(),"",policyQuestionList.get(panelNumber).getQuestionText());
MyPasswordQuestionsPanel panel=new MyPasswordQuestionsPanel(ID_PASSWORD_QUESTIONS_PANEL+ panelNumber,a);
pqPanels.add(panel);
panelNumber++;
}
}
/**
* method for get existing questions and answer from user credentials
* @author oguzhan
* @param userQuestionList
* @param policyQuestionList
* @param panelNumber
*/
public void executePasswordQuestionsAndAnswers(List<SecurityQuestionAnswerDTO> userQuestionList,List<SecurityQuestionDefinitionType> policyQuestionList, int panelNumber ){
int userQuest =0;
LOGGER.debug("executePasswordQuestionsAndAnswers");
for (Iterator iterator = policyQuestionList.iterator(); iterator.hasNext();) {
/* Loop for finding the Existing Questions
* and Answers according to Policy*/
SecurityQuestionDefinitionType securityQuestionDefinitionType = (SecurityQuestionDefinitionType) iterator
.next();
//user's question List loop to match the questions
for(int i=userQuest;i<userQuestionList.size();i++){
if(userQuestionList.get(i).getPwdQuestion().trim().compareTo(securityQuestionDefinitionType.getIdentifier().trim())==0)
{
SecurityQuestionAnswerDTO a=new SecurityQuestionAnswerDTO(userQuestionList.get(i).getPwdQuestion(),userQuestionList.get(i).getPwdAnswer(),userQuestionList.get(i).getQuestionItself());
a= checkIfQuestionisValidSingle(a, securityQuestionDefinitionType);
MyPasswordQuestionsPanel panel=new MyPasswordQuestionsPanel(ID_PASSWORD_QUESTIONS_PANEL+ panelNumber,a);
pqPanels.add(panel);
panelNumber++;
userQuest++;
break;
}
else if(userQuestionList.get(i).getPwdQuestion().trim().compareTo(securityQuestionDefinitionType.getIdentifier().trim())!=0){
SecurityQuestionAnswerDTO a=new SecurityQuestionAnswerDTO(policyQuestionList.get(panelNumber).getIdentifier(),"",policyQuestionList.get(panelNumber).getQuestionText());
a.setQuestionItself(securityQuestionDefinitionType.getQuestionText());
userQuestionList.get(i).setPwdQuestion(securityQuestionDefinitionType.getIdentifier().trim());
MyPasswordQuestionsPanel panel=new MyPasswordQuestionsPanel(ID_PASSWORD_QUESTIONS_PANEL+ panelNumber,a);
pqPanels.add(panel);
panelNumber++;
userQuest++;
break;
}
}
}
}
public ListView<MyPasswordQuestionsPanel> getPanels(List<MyPasswordQuestionsPanel> p){
ListView lw = new ListView(ID_PASSWORD_QUESTIONS_PANEL,p){
@Override
protected void populateItem(ListItem item) {
item.add((MyPasswordQuestionsPanel)item.getModelObject());
}
};
return lw;
}
public void initButtons(Form mainForm){
AjaxSubmitButton save = new AjaxSubmitButton(ID_SAVE, createStringResource("PageBase.button.save")) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
savePerformed(target);
}
};
mainForm.add(save);
AjaxButton back = new AjaxButton(ID_BACK, createStringResource("PageBase.button.back")) {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
cancelPerformed(target);
}
};
mainForm.add(back);
}
private void savePerformed(AjaxRequestTarget target) {
/*
* Oguzhan: added target variable to the updateQuestions method.
*/
updateQuestions(SecurityUtils.getPrincipalUser().getOid(), target);
}
private void cancelPerformed(AjaxRequestTarget target){
setResponsePage(getMidpointApplication().getHomePage());
}
private ObjectWrapper loadUserWrapper(PrismObject<UserType> userToEdit) {
OperationResult result = new OperationResult(OPERATION_LOAD_USER);
PrismObject<UserType> user = null;
try {
Collection options = SelectorOptions.createCollection(UserType.F_CREDENTIALS,
GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE));
Task task = createSimpleTask(OPERATION_LOAD_USER);
user = getModelService().getObject(UserType.class, SecurityUtils.getPrincipalUser().getOid(), options, task, result);
result.recordSuccess();
} catch (Exception ex) {
result.recordFatalError("Couldn't get user.", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load user PageMyQuestions", ex);
}
showResult(result, false);
if (user == null) {
throw new RestartResponseException(PageDashboard.class);
}
ContainerStatus status = ContainerStatus.MODIFYING;
ObjectWrapperFactory owf = new ObjectWrapperFactory(this);
ObjectWrapper wrapper;
try{
wrapper = owf.createObjectWrapper("pageMyPasswordQuestions.userDetails", null, user, status);
} catch (Exception ex){
result.recordFatalError("Couldn't get user.", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load user", ex);
wrapper = owf.createObjectWrapper("pageMyPasswordQuestions.userDetails", null, user, null, null, status, false);
}
// ObjectWrapper wrapper = new ObjectWrapper("pageUser.userDetails", null, user, status);
showResult(wrapper.getResult(), false);
return wrapper;
}
private SecurityQuestionAnswerDTO checkIfQuestionisValid(SecurityQuestionAnswerDTO questionIdentifier,List<SecurityQuestionDefinitionType> securityQuestionList){
for (Iterator iterator = securityQuestionList.iterator(); iterator
.hasNext();) {
SecurityQuestionDefinitionType securityQuestionDefinitionType = (SecurityQuestionDefinitionType) iterator
.next();
LOGGER.debug("List For"+securityQuestionDefinitionType.getIdentifier().trim());
if(securityQuestionDefinitionType.getIdentifier().trim().equalsIgnoreCase((questionIdentifier.getPwdQuestion().trim()))){
questionIdentifier.setQuestionItself(securityQuestionDefinitionType.getQuestionText());
LOGGER.info(": TRUE QUESTION");
return questionIdentifier;
}else{
return null;
}
}
return null;
}
private SecurityQuestionAnswerDTO checkIfQuestionisValidSingle(SecurityQuestionAnswerDTO questionIdentifier,SecurityQuestionDefinitionType securityQuestion){
if(securityQuestion.getIdentifier().trim().compareTo(questionIdentifier.getPwdQuestion().trim())==0){
questionIdentifier.setQuestionItself(securityQuestion.getQuestionText());
//LOGGER.info("\n\n: TRUE QUESTION");
return questionIdentifier;
}else{
return null;
}
}
private void updateQuestions(String useroid, AjaxRequestTarget target){
Task task = createSimpleTask(OPERATION_SAVE_QUESTIONS);
OperationResult result = new OperationResult(OPERATION_SAVE_QUESTIONS);
SchemaRegistry registry = getPrismContext().getSchemaRegistry();
SecurityQuestionAnswerType[] answerTypeList=new SecurityQuestionAnswerType[questionNumber];
try {
int listnum=0;
for (Iterator iterator = pqPanels.iterator(); iterator.hasNext();) {
MyPasswordQuestionsPanel type = (MyPasswordQuestionsPanel) iterator.next();
SecurityQuestionAnswerType answerType = new SecurityQuestionAnswerType();
ProtectedStringType answer = new ProtectedStringType();
answer.setClearValue(((TextField<String>)type.get(MyPasswordQuestionsPanel.F_ANSWER)).getModelObject());
answerType.setQuestionAnswer(answer);
//used apache's unescapeHtml method for special chars like \'
String results = StringEscapeUtils.unescapeHtml((type.get(MyPasswordQuestionsPanel.F_QUESTION)).getDefaultModelObjectAsString());
answerType.setQuestionIdentifier(getQuestionIdentifierFromQuestion(results));
answerTypeList[listnum]=answerType;
listnum++;
}
//if(answerTypeList.length !=)
// fill in answerType data here
ItemPath path = new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_SECURITY_QUESTIONS, SecurityQuestionsCredentialsType.F_QUESTION_ANSWER);
ObjectDelta<UserType> objectDelta = ObjectDelta.createModificationReplaceContainer(UserType.class, useroid,
path, getPrismContext(), answerTypeList);
Collection<ObjectDelta<? extends ObjectType>> deltas = MiscSchemaUtil.createCollection(objectDelta);
getModelService().executeChanges(deltas, null, task, result);
/*
System.out.println("getModel");
Collection<ObjectDelta<? extends ObjectType>> deltas = new ArrayList<ObjectDelta<? extends ObjectType>>();
PasswordQuestionsDto dto = new PasswordQuestionsDto();
PrismObjectDefinition objDef =registry.findObjectDefinitionByCompileTimeClass(UserType.class);
Class<? extends ObjectType> type = UserType.class;
final ItemPath valuePath = new ItemPath(SchemaConstantsGenerated.C_CREDENTIALS,
CredentialsType.F_SECURITY_QUESTIONS, SecurityQuestionsCredentialsType.F_QUESTION_ANSWER);
SecurityQuestionAnswerType secQuesAnsType= new SecurityQuestionAnswerType();
ProtectedStringType protStrType= new ProtectedStringType();
protStrType.setClearValue("deneme");
secQuesAnsType.setQuestionAnswer(protStrType);
dto.setSecurityAnswers(new ArrayList<SecurityQuestionAnswerType>());
dto.getSecurityAnswers().add(secQuesAnsType);
PropertyDelta delta = PropertyDelta.createModificationReplaceProperty(valuePath, objDef, dto.getSecurityAnswers().get(0).getQuestionAnswer());
// PropertyDelta delta= PropertyDelta.createModifica
System.out.println("Update Questions3");
deltas.add(ObjectDelta.createModifyDelta(useroid, delta, type, getPrismContext()));
System.out.println("Update Questions4");
getModelService().executeChanges(deltas, null, createSimpleTask(OPERATION_SAVE_QUESTIONS), result);
System.out.println("Update Questions5");
*/
success(getString("message.success"));
target.add(getFeedbackPanel());
} catch(Exception ex){
error(getString("message.error"));
target.add(getFeedbackPanel());
ex.printStackTrace();
}
}
private String getQuestionIdentifierFromQuestion(String questionItself){
//LOGGER.info("\n\n QUESTION: "+questionItself);
for (Iterator iterator = policyQuestionList.iterator(); iterator
.hasNext();) {
SecurityQuestionDefinitionType securityQuestionDefinitionType = (SecurityQuestionDefinitionType) iterator
.next();
if(questionItself.equalsIgnoreCase(securityQuestionDefinitionType.getQuestionText()))
return securityQuestionDefinitionType.getIdentifier();
}
return null;
}
public PageBase getPageBase() {
return (PageBase) getPage();
}
}