use of com.novell.ldapchai.cr.ChallengeSet in project ldapchai by ldapchai.
the class NmasResponseSet method readNmasUserResponseSet.
static NmasResponseSet readNmasUserResponseSet(final ChaiUser theUser) throws ChaiUnavailableException, ChaiValidationException {
final GetLoginConfigRequest request = new GetLoginConfigRequest();
request.setObjectDN(theUser.getEntryDN());
request.setTag("ChallengeResponseQuestions");
request.setMethodID(NMASChallengeResponse.METHOD_ID);
request.setMethodIDLen(NMASChallengeResponse.METHOD_ID.length * 4);
try {
final ExtendedResponse response = theUser.getChaiProvider().extendedOperation(request);
final byte[] responseValue = response.getEncodedValue();
if (responseValue == null) {
return null;
}
final String xmlString = new String(responseValue, "UTF8");
LOGGER.trace("[parse v3]: read ChallengeResponseQuestions from server: " + xmlString);
ChallengeSet cs = null;
int parseAttempts = 0;
final StringBuilder parsingErrorMsg = new StringBuilder();
{
final int beginIndex = xmlString.indexOf("<");
if (beginIndex > 0) {
try {
parseAttempts++;
final String xmlSubstring = xmlString.substring(beginIndex, xmlString.length());
LOGGER.trace("attempting parse of index stripped value: " + xmlSubstring);
cs = parseNmasUserResponseXML(xmlSubstring);
LOGGER.trace("successfully parsed nmas ChallengeResponseQuestions response after index " + beginIndex);
} catch (JDOMException e) {
if (parsingErrorMsg.length() > 0) {
parsingErrorMsg.append(", ");
}
parsingErrorMsg.append("error parsing index stripped value: ").append(e.getMessage());
LOGGER.trace("unable to parse index stripped ChallengeResponseQuestions nmas response; error: " + e.getMessage());
}
}
}
if (cs == null) {
if (xmlString.startsWith("<?xml")) {
try {
parseAttempts++;
cs = parseNmasUserResponseXML(xmlString);
} catch (JDOMException e) {
parsingErrorMsg.append("error parsing raw value: ").append(e.getMessage());
LOGGER.trace("unable to parse raw ChallengeResponseQuestions nmas response; will retry after stripping header; error: " + e.getMessage());
}
LOGGER.trace("successfully parsed full nmas ChallengeResponseQuestions response");
}
}
if (cs == null) {
if (xmlString.length() > 16) {
// first 16 bytes are non-xml header.
final String strippedXml = xmlString.substring(16);
try {
parseAttempts++;
cs = parseNmasUserResponseXML(strippedXml);
LOGGER.trace("successfully parsed full nmas ChallengeResponseQuestions response");
} catch (JDOMException e) {
if (parsingErrorMsg.length() > 0) {
parsingErrorMsg.append(", ");
}
parsingErrorMsg.append("error parsing header stripped value: ").append(e.getMessage());
LOGGER.trace("unable to parse stripped ChallengeResponseQuestions nmas response; error: " + e.getMessage());
}
}
}
if (cs == null) {
final String logMsg = "unable to parse nmas ChallengeResponseQuestions: " + parsingErrorMsg;
if (parseAttempts > 0 && xmlString.length() > 16) {
LOGGER.error(logMsg);
} else {
LOGGER.trace(logMsg);
}
return null;
}
final Map<Challenge, String> crMap = new HashMap<Challenge, String>();
for (final Challenge loopChallenge : cs.getChallenges()) {
crMap.put(loopChallenge, null);
}
return new NmasResponseSet(crMap, cs.getLocale(), cs.getMinRandomRequired(), AbstractResponseSet.STATE.READ, theUser, cs.getIdentifier());
} catch (ChaiOperationException e) {
LOGGER.error("error reading nmas user response for " + theUser.getEntryDN() + ", error: " + e.getMessage());
} catch (IOException e) {
LOGGER.error("error reading nmas user response for " + theUser.getEntryDN() + ", error: " + e.getMessage());
}
return null;
}
use of com.novell.ldapchai.cr.ChallengeSet in project pwm by pwm-project.
the class CrService method validateResponses.
public void validateResponses(final ChallengeSet challengeSet, final Map<Challenge, String> responseMap, final int minRandomRequiredSetup) throws PwmDataValidationException, PwmUnrecoverableException {
// strip null keys from responseMap;
responseMap.keySet().removeIf(Objects::isNull);
{
// check for missing question texts
for (final Challenge challenge : responseMap.keySet()) {
if (!challenge.isAdminDefined()) {
final String text = challenge.getChallengeText();
if (text == null || text.length() < 1) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_MISSING_CHALLENGE_TEXT);
throw new PwmDataValidationException(errorInformation);
}
}
}
}
{
// check responses against wordlist
final WordlistManager wordlistManager = pwmApplication.getWordlistManager();
if (wordlistManager.status() == PwmService.STATUS.OPEN) {
for (final Map.Entry<Challenge, String> entry : responseMap.entrySet()) {
final Challenge loopChallenge = entry.getKey();
if (loopChallenge.isEnforceWordlist()) {
final String answer = entry.getValue();
if (wordlistManager.containsWord(answer)) {
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_RESPONSE_WORDLIST, null, new String[] { loopChallenge.getChallengeText() });
throw new PwmDataValidationException(errorInfo);
}
}
}
}
}
{
// check for duplicate questions. need to check the actual req params because the following dupes wont populate duplicates
final Set<String> userQuestionTexts = new HashSet<>();
for (final Challenge challenge : responseMap.keySet()) {
final String text = challenge.getChallengeText();
if (text != null) {
if (userQuestionTexts.contains(text.toLowerCase())) {
final String errorMsg = "duplicate challenge text: " + text;
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CHALLENGE_DUPLICATE, errorMsg, new String[] { text });
throw new PwmDataValidationException(errorInformation);
} else {
userQuestionTexts.add(text.toLowerCase());
}
}
}
}
int randomCount = 0;
for (final Challenge loopChallenge : responseMap.keySet()) {
if (!loopChallenge.isRequired()) {
randomCount++;
}
}
if (minRandomRequiredSetup == 0) {
// if using recover style, then all readResponseSet must be supplied at this point.
if (randomCount < challengeSet.getRandomChallenges().size()) {
final String errorMsg = "all randoms required, but not all randoms are completed";
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_MISSING_RANDOM_RESPONSE, errorMsg);
throw new PwmDataValidationException(errorInfo);
}
}
if (randomCount < minRandomRequiredSetup) {
final String errorMsg = minRandomRequiredSetup + " randoms required, but not only " + randomCount + " randoms are completed";
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_MISSING_RANDOM_RESPONSE, errorMsg);
throw new PwmDataValidationException(errorInfo);
}
if (JavaHelper.isEmpty(responseMap)) {
final String errorMsg = "empty response set";
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_MISSING_PARAMETER, errorMsg);
throw new PwmDataValidationException(errorInfo);
}
}
use of com.novell.ldapchai.cr.ChallengeSet in project pwm by pwm-project.
the class ForgottenPasswordUtil method initBogusForgottenPasswordBean.
static void initBogusForgottenPasswordBean(final PwmRequest pwmRequest) throws PwmUnrecoverableException {
final ForgottenPasswordBean forgottenPasswordBean = ForgottenPasswordServlet.forgottenPasswordBean(pwmRequest);
forgottenPasswordBean.setUserIdentity(null);
forgottenPasswordBean.setPresentableChallengeSet(null);
final List<Challenge> challengeList = new ArrayList<>();
{
final String firstProfile = pwmRequest.getConfig().getChallengeProfileIDs().iterator().next();
final ChallengeSet challengeSet = pwmRequest.getConfig().getChallengeProfile(firstProfile, PwmConstants.DEFAULT_LOCALE).getChallengeSet();
challengeList.addAll(challengeSet.getRequiredChallenges());
for (int i = 0; i < challengeSet.getMinRandomRequired(); i++) {
challengeList.add(challengeSet.getRandomChallenges().get(i));
}
}
final List<FormConfiguration> formData = new ArrayList<>();
{
int counter = 0;
for (Challenge challenge : challengeList) {
final FormConfiguration formConfiguration = FormConfiguration.builder().name("challenge" + counter++).type(FormConfiguration.Type.text).labels(Collections.singletonMap("", challenge.getChallengeText())).minimumLength(challenge.getMinLength()).maximumLength(challenge.getMaxLength()).source(FormConfiguration.Source.bogus).build();
formData.add(formConfiguration);
}
}
forgottenPasswordBean.setAttributeForm(formData);
forgottenPasswordBean.setBogusUser(true);
{
final String profileID = pwmRequest.getConfig().getForgottenPasswordProfiles().keySet().iterator().next();
forgottenPasswordBean.setForgottenPasswordProfileID(profileID);
}
final ForgottenPasswordBean.RecoveryFlags recoveryFlags = new ForgottenPasswordBean.RecoveryFlags(false, Collections.singleton(IdentityVerificationMethod.ATTRIBUTES), Collections.emptySet(), 0);
forgottenPasswordBean.setRecoveryFlags(recoveryFlags);
}
use of com.novell.ldapchai.cr.ChallengeSet in project pwm by pwm-project.
the class ForgottenPasswordUtil method verifyRequirementsForAuthMethod.
static void verifyRequirementsForAuthMethod(final PwmRequest pwmRequest, final ForgottenPasswordBean forgottenPasswordBean, final IdentityVerificationMethod recoveryVerificationMethods) throws PwmUnrecoverableException {
switch(recoveryVerificationMethods) {
case TOKEN:
{
ForgottenPasswordUtil.figureAvailableTokenDestinations(pwmRequest, forgottenPasswordBean);
}
break;
case ATTRIBUTES:
{
final List<FormConfiguration> formConfiguration = forgottenPasswordBean.getAttributeForm();
if (formConfiguration == null || formConfiguration.isEmpty()) {
final String errorMsg = "user is required to complete LDAP attribute check, yet there are no LDAP attribute form items configured";
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_INVALID_CONFIG, errorMsg);
throw new PwmUnrecoverableException(errorInformation);
}
}
break;
case OTP:
{
final UserInfo userInfo = ForgottenPasswordUtil.readUserInfo(pwmRequest, forgottenPasswordBean);
if (userInfo.getOtpUserRecord() == null) {
final String errorMsg = "could not find a one time password configuration for " + userInfo.getUserIdentity();
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_NO_OTP_CONFIGURATION, errorMsg);
throw new PwmUnrecoverableException(errorInformation);
}
}
break;
case CHALLENGE_RESPONSES:
{
final UserInfo userInfo = ForgottenPasswordUtil.readUserInfo(pwmRequest, forgottenPasswordBean);
final ResponseSet responseSet = ForgottenPasswordUtil.readResponseSet(pwmRequest, forgottenPasswordBean);
if (responseSet == null) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_RESPONSES_NORESPONSES);
throw new PwmUnrecoverableException(errorInformation);
}
final ChallengeSet challengeSet = userInfo.getChallengeProfile().getChallengeSet();
try {
if (responseSet.meetsChallengeSetRequirements(challengeSet)) {
if (challengeSet.getRequiredChallenges().isEmpty() && (challengeSet.getMinRandomRequired() <= 0)) {
final String errorMsg = "configured challenge set policy for " + userInfo.getUserIdentity().toString() + " is empty, user not qualified to recover password";
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_NO_CHALLENGES, errorMsg);
throw new PwmUnrecoverableException(errorInformation);
}
}
} catch (ChaiValidationException e) {
final String errorMsg = "stored response set for user '" + userInfo.getUserIdentity() + "' do not meet current challenge set requirements: " + e.getLocalizedMessage();
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_RESPONSES_NORESPONSES, errorMsg);
throw new PwmUnrecoverableException(errorInformation);
}
}
break;
default:
// continue, assume no data requirements for method.
break;
}
}
use of com.novell.ldapchai.cr.ChallengeSet in project pwm by pwm-project.
the class SetupResponsesServlet method setupResponses.
private void setupResponses(final PwmRequest pwmRequest, final boolean helpdeskMode) throws PwmUnrecoverableException, IOException, ServletException, ChaiUnavailableException {
final SetupResponsesBean setupResponsesBean = getSetupResponseBean(pwmRequest);
final SetupResponsesBean.SetupData setupData = helpdeskMode ? setupResponsesBean.getHelpdeskResponseData() : setupResponsesBean.getResponseData();
final ChallengeSet challengeSet = setupData.getChallengeSet();
final Map<Challenge, String> responseMap;
try {
// build a response set based on the user's challenge set and the html form response.
responseMap = readResponsesFromHttpRequest(pwmRequest, setupData);
// test the responses.
final int minRandomRequiredSetup = setupData.getMinRandomSetup();
pwmRequest.getPwmApplication().getCrService().validateResponses(challengeSet, responseMap, minRandomRequiredSetup);
} catch (PwmDataValidationException e) {
LOGGER.debug(pwmRequest, "error with new " + (helpdeskMode ? "helpdesk" : "user") + " responses: " + e.getErrorInformation().toDebugStr());
setLastError(pwmRequest, e.getErrorInformation());
return;
}
LOGGER.trace(pwmRequest, (helpdeskMode ? "helpdesk" : "user") + " responses are acceptable");
if (helpdeskMode) {
setupResponsesBean.getHelpdeskResponseData().setResponseMap(responseMap);
setupResponsesBean.setHelpdeskResponsesSatisfied(true);
} else {
setupResponsesBean.getResponseData().setResponseMap(responseMap);
setupResponsesBean.setResponsesSatisfied(true);
}
}
Aggregations