package at.gv.egovernment.moa.id.configuration.struts.action; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.joda.time.DateTime; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; import org.opensaml.saml2.core.Attribute; import org.opensaml.saml2.core.AttributeStatement; import org.opensaml.saml2.core.Conditions; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.Subject; import org.opensaml.saml2.core.SubjectConfirmation; import org.opensaml.saml2.core.SubjectConfirmationData; import org.opensaml.saml2.metadata.IDPSSODescriptor; import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCredentialResolverFactory; import org.opensaml.security.MetadataCriteria; import org.opensaml.security.SAMLSignatureProfileValidator; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; import org.opensaml.xml.parse.BasicParserPool; import org.opensaml.xml.security.CriteriaSet; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.criteria.EntityIDCriteria; import org.opensaml.xml.security.criteria.UsageCriteria; import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver; import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; import org.opensaml.xml.security.keyinfo.KeyInfoProvider; import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; import com.opensymphony.xwork2.ActionSupport; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBRead; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.dao.config.OnlineApplication; import at.gv.egovernment.moa.id.commons.db.dao.config.UserDatabase; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.configuration.Constants; import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser; import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider; import at.gv.egovernment.moa.id.configuration.data.UserDatabaseFrom; import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException; import at.gv.egovernment.moa.id.configuration.helper.AuthenticationHelper; import at.gv.egovernment.moa.id.configuration.helper.DateTimeHelper; import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper; import at.gv.egovernment.moa.id.configuration.helper.MailHelper; import at.gv.egovernment.moa.id.configuration.validation.ValidationHelper; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.util.MiscUtil; public class IndexAction extends ActionSupport implements ServletRequestAware, ServletResponseAware { private static final long serialVersionUID = -2781497863862504896L; private static final Logger log = Logger.getLogger(IndexAction.class); private HttpServletRequest request; private HttpServletResponse response; private String password; private String username; private UserDatabaseFrom user = null; private AuthenticatedUser authUser = null; private String formID; private String ssologouturl; public String start() { return Constants.STRUTS_SUCCESS; } public String authenticate() { String key = null; if (MiscUtil.isNotEmpty(username)) { if (ValidationHelper.containsPotentialCSSCharacter(username, false)) { log.warn("Username contains potentail XSS characters: " + username); addActionError(LanguageHelper.getErrorString("validation.edituser.username.valid", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)} )); return Constants.STRUTS_ERROR; } } else { log.warn("Username is empty"); addActionError(LanguageHelper.getErrorString("validation.edituser.username.empty")); return Constants.STRUTS_ERROR; } if (MiscUtil.isEmpty(password)) { log.warn("Password is empty"); addActionError(LanguageHelper.getErrorString("validation.edituser.password.empty")); return Constants.STRUTS_ERROR; } else { key = AuthenticationHelper.generateKeyFormPassword(password); if (key == null) { addActionError(LanguageHelper.getErrorString("validation.edituser.password.valid")); return Constants.STRUTS_ERROR; } } UserDatabase dbuser = ConfigurationDBRead.getUserWithUserName(username); if (dbuser == null) { log.warn("Unknown Username"); addActionError(LanguageHelper.getErrorString("webpages.index.login.notallowed")); return Constants.STRUTS_ERROR; } else { //TODO: maybe remove this default value in a later version if (dbuser.isIsUsernamePasswordAllowed() == null) dbuser.setIsUsernamePasswordAllowed(true); if (!dbuser.isIsActive() || !dbuser.isIsUsernamePasswordAllowed()) { log.warn("Username " + dbuser.getUsername() + " is not active or Username/Password login is not allowed"); addActionError(LanguageHelper.getErrorString("webpages.index.login.notallowed")); return Constants.STRUTS_ERROR; } if (!dbuser.getPassword().equals(key)) { log.warn("Username " + dbuser.getUsername() + " use a false password"); addActionError(LanguageHelper.getErrorString("webpages.index.login.notallowed")); return Constants.STRUTS_ERROR; } //TODO: maybe remove this default value in a later version boolean ismandateuser = false; if (dbuser.isIsMandateUser() != null) ismandateuser = dbuser.isIsMandateUser(); AuthenticatedUser authuser = new AuthenticatedUser( dbuser.getHjid(), dbuser.getGivenname(), dbuser.getFamilyname(), dbuser.getInstitut(), dbuser.getUsername(), true, dbuser.isIsAdmin(), ismandateuser, false); Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin()); if (date != null) authuser.setLastLogin(date);; dbuser.setLastLogin(DateTimeHelper.getDateTime(new Date())); try { ConfigurationDBUtils.saveOrUpdate(dbuser); } catch (MOADatabaseException e) { log.warn("UserDatabase communicaton error", e); addActionError(LanguageHelper.getErrorString("error.login")); return Constants.STRUTS_ERROR; } finally { ConfigurationDBUtils.closeSession(); } request.getSession().setAttribute(Constants.SESSION_AUTH, authuser); return Constants.STRUTS_SUCCESS; } } public String pvp2login() { String method = request.getMethod(); HttpSession session = request.getSession(); if (session == null) { log.info("NO HTTP Session"); return Constants.STRUTS_ERROR; } String authID = (String) session.getAttribute(Constants.SESSION_PVP2REQUESTID); session.setAttribute(Constants.SESSION_PVP2REQUESTID, null); if (method.equals("POST")) { try { ConfigurationProvider config = ConfigurationProvider.getInstance(); //Decode with HttpPost Binding HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool()); BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext .setInboundMessageTransport(new HttpServletRequestAdapter( request)); decode.decode(messageContext); Response samlResponse = (Response) messageContext.getInboundMessage(); Signature sign = samlResponse.getSignature(); if (sign == null) { log.info("Only http POST Requests can be used"); addActionError(LanguageHelper.getErrorString("error.login")); return Constants.STRUTS_ERROR; } //Validate Signature SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); profileValidator.validate(sign); //Verify Signature List keyInfoProvider = new ArrayList(); keyInfoProvider.add(new DSAKeyValueProvider()); keyInfoProvider.add(new RSAKeyValueProvider()); keyInfoProvider.add(new InlineX509DataProvider()); KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver( keyInfoProvider); MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory(); MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(config.getMetaDataProvier()); CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName())); criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver); trustEngine.validate(sign, criteriaSet); log.info("PVP2 Assertion is valid"); if (samlResponse.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { List saml2assertions = samlResponse.getAssertions(); if (MiscUtil.isEmpty(authID)) { log.info("NO AuthRequestID"); return Constants.STRUTS_ERROR; } for (org.opensaml.saml2.core.Assertion saml2assertion : saml2assertions) { Subject subject = saml2assertion.getSubject(); List subjectconformlist = subject.getSubjectConfirmations(); for (SubjectConfirmation el : subjectconformlist) { if (el.getMethod().equals(SubjectConfirmation.METHOD_BEARER)) { SubjectConfirmationData date = el.getSubjectConfirmationData(); if (!authID.equals(date.getInResponseTo())) { log.warn("PVPRequestID does not match PVP2 Assertion ID!"); return Constants.STRUTS_ERROR; } } } Conditions conditions = saml2assertion.getConditions(); DateTime notbefore = conditions.getNotBefore(); DateTime notafter = conditions.getNotOnOrAfter(); if ( notbefore.isAfterNow() || notafter.isBeforeNow() ) { log.warn("PVP2 Assertion is out of Date"); return Constants.STRUTS_ERROR; } NameID nameID = subject.getNameID(); if (nameID == null) { log.warn("No NameID element in PVP2 assertion!"); return Constants.STRUTS_ERROR; } String bpkwbpk = nameID.getNameQualifier() + "+" + nameID.getValue(); //search user UserDatabase dbuser = ConfigurationDBRead.getUserWithUserBPKWBPK(bpkwbpk); if (dbuser == null) { log.info("No user found with bpk/wbpk " + bpkwbpk); //read PVP2 assertion attributes; user = new UserDatabaseFrom(); user.setActive(false); user.setAdmin(false); user.setBpk(bpkwbpk); user.setIsusernamepasswordallowed(false); user.setIsmandateuser(false); user.setPVPGenerated(true); authUser = new AuthenticatedUser(); authUser.setAdmin(false); authUser.setAuthenticated(false); authUser.setLastLogin(null); authUser.setUserID(-1); authUser.setUserName(null); authUser.setPVP2Login(true); authUser.setMandateUser(false); //loop through the nodes to get what we want List attributeStatements = saml2assertion.getAttributeStatements(); for (int i = 0; i < attributeStatements.size(); i++) { List attributes = attributeStatements.get(i).getAttributes(); for (int x = 0; x < attributes.size(); x++) { String strAttributeName = attributes.get(x).getDOM().getAttribute("Name"); if (strAttributeName.equals(PVPConstants.PRINCIPAL_NAME_NAME)) { user.setFamilyName(attributes.get(x).getAttributeValues().get(0).getDOM().getTextContent()); authUser.setFamilyName(user.getFamilyName()); } if (strAttributeName.equals(PVPConstants.GIVEN_NAME_NAME)) { user.setGivenName(attributes.get(x).getAttributeValues().get(0).getDOM().getTextContent()); authUser.setGivenName(user.getGivenName()); } if (strAttributeName.equals(PVPConstants.MANDATE_TYPE_NAME)) { authUser.setMandateUser(true); user.setIsmandateuser(true); } if (strAttributeName.equals(PVPConstants.MANDATE_LEG_PER_FULL_NAME_NAME)) { user.setInstitut(attributes.get(x).getAttributeValues().get(0).getDOM().getTextContent()); authUser.setInstitute(user.getInstitut()); } } } //set Random value formID = Random.nextRandom(); session.setAttribute(Constants.SESSION_FORMID, formID); session.setAttribute(Constants.SESSION_FORM, user); session.setAttribute(Constants.SESSION_AUTH, authUser); ConfigurationDBUtils.closeSession(); return Constants.STRUTS_NEWUSER; } else { if (!dbuser.isIsActive()) { if (!dbuser.isIsMailAddressVerified()) { formID = Random.nextRandom(); session.setAttribute(Constants.SESSION_FORMID, formID); user = new UserDatabaseFrom(dbuser); authUser = new AuthenticatedUser( dbuser.getHjid(), dbuser.getGivenname(), dbuser.getFamilyname(), dbuser.getInstitut(), dbuser.getUsername(), false, false, dbuser.isIsMandateUser(), true); session.setAttribute(Constants.SESSION_FORM, user); session.setAttribute(Constants.SESSION_AUTH, authUser); return Constants.STRUTS_NEWUSER; } log.info("User with bpk/wbpk " + bpkwbpk + " is not active"); addActionError(LanguageHelper.getErrorString("webpages.index.username.notactive")); return Constants.STRUTS_ERROR; } //TODO: maybe remove this default value in a later version boolean ismandateuser = false; if (dbuser.isIsMandateUser() != null) ismandateuser = dbuser.isIsMandateUser(); authUser = new AuthenticatedUser( dbuser.getHjid(), dbuser.getGivenname(), dbuser.getFamilyname(), dbuser.getInstitut(), dbuser.getUsername(), true, dbuser.isIsAdmin(), ismandateuser, true); Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin()); if (date != null) authUser.setLastLogin(date);; dbuser.setLastLogin(DateTimeHelper.getDateTime(new Date())); try { ConfigurationDBUtils.saveOrUpdate(dbuser); } catch (MOADatabaseException e) { log.warn("UserDatabase communicaton error", e); addActionError(LanguageHelper.getErrorString("error.login")); return Constants.STRUTS_ERROR; } finally { ConfigurationDBUtils.closeSession(); } session.setAttribute(Constants.SESSION_AUTH, authUser); return Constants.STRUTS_SUCCESS; } } log.info("PVP2 Assertion was maybe not well formed, because no Assertion element could be found."); addActionError(LanguageHelper.getErrorString("error.login.internal")); return Constants.STRUTS_ERROR; } else { log.info("Receive Error Assertion."); addActionError(LanguageHelper.getErrorString("error.login")); return Constants.STRUTS_ERROR; } } catch (Exception e) { log.warn("An internal error occurs.", e); addActionError(LanguageHelper.getErrorString("error.login.internal")); return Constants.STRUTS_ERROR; } } else { log.info("Only http POST Requests can be used"); addActionError(LanguageHelper.getErrorString("error.login.internal")); return Constants.STRUTS_ERROR; } } public String requestNewUser() { HttpSession session = request.getSession(); if (session == null) { log.warn("No active Session found"); return Constants.STRUTS_ERROR; } Object formidobj = session.getAttribute(Constants.SESSION_FORMID); if (formidobj != null && formidobj instanceof String) { String formid = (String) formidobj; if (!formid.equals(formID)) { log.warn("FormIDs does not match. Some suspect Form is received from user " + authUser.getFamilyName() + authUser.getGivenName() + authUser.getUserID()); return Constants.STRUTS_ERROR; } } else { log.warn("FormIDs does not match. Some suspect Form is received from user " + authUser.getFamilyName() + authUser.getGivenName() + authUser.getUserID()); return Constants.STRUTS_ERROR; } session.setAttribute(Constants.SESSION_FORMID, null); Object sessionformobj = session.getAttribute(Constants.SESSION_FORM); if (sessionformobj != null && sessionformobj instanceof UserDatabaseFrom) { UserDatabaseFrom sessionform = (UserDatabaseFrom) sessionformobj; Object authUserObj = session.getAttribute(Constants.SESSION_AUTH); authUser = (AuthenticatedUser) authUserObj; if (user == null) { log.warn("No form transmited"); return Constants.STRUTS_ERROR; } //get UserID String useridobj = user.getUserID(); long userID = -1; if (MiscUtil.isEmpty(useridobj)) { userID = -1; } else { if (!ValidationHelper.validateOAID(useridobj)){ log.warn("User with ID " + authUser.getUserID() + " would access UserDatabase ID " + useridobj); addActionError(LanguageHelper.getErrorString("errors.edit.user.notallowed", request)); return Constants.STRUTS_ERROR; } userID = Long.valueOf(useridobj); } String check; if (!sessionform.isIsmandateuser()) { check = user.getInstitut(); if (MiscUtil.isNotEmpty(check)) { if (ValidationHelper.containsPotentialCSSCharacter(check, false)) { log.warn("Organisation contains potentail XSS characters: " + check); addActionError(LanguageHelper.getErrorString("validation.edituser.institut.valid", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)} )); } } else { log.warn("Organisation is empty"); addActionError(LanguageHelper.getErrorString("validation.edituser.institut.empty")); } } check = user.getMail(); if (MiscUtil.isNotEmpty(check)) { if (!ValidationHelper.isEmailAddressFormat(check)) { log.warn("Mailaddress is not valid: " + check); addActionError(LanguageHelper.getErrorString("validation.edituser.mail.valid", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)} )); } } else { log.warn("Mailaddress is empty"); addActionError(LanguageHelper.getErrorString("validation.edituser.mail.empty")); } check = user.getPhone(); if (MiscUtil.isNotEmpty(check)) { if (ValidationHelper.containsPotentialCSSCharacter(check, false)) { log.warn("Phonenumber contains potentail XSS characters: " + check); addActionError(LanguageHelper.getErrorString("validation.edituser.phone.valid", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)} )); } } else { log.warn("Phonenumber is empty"); addActionError(LanguageHelper.getErrorString("validation.edituser.phone.empty")); } if (hasActionErrors()) { log.info("Some form errors found. Send user back to form"); user.setPVPGenerated(true); user.setFamilyName(sessionform.getFamilyName()); user.setGivenName(sessionform.getGivenName()); user.setIsmandateuser(sessionform.isIsmandateuser()); user.setBpk(sessionform.getBpk()); if (sessionform.isIsmandateuser()) user.setInstitut(sessionform.getInstitut()); formID = Random.nextRandom(); session.setAttribute(Constants.SESSION_FORMID, formID); return Constants.STRUTS_NEWUSER; } UserDatabase dbuser; if (userID < 0) { dbuser = new UserDatabase(); dbuser.setBpk(sessionform.getBpk()); dbuser.setFamilyname(sessionform.getFamilyName()); dbuser.setGivenname(sessionform.getGivenName()); if (sessionform.isIsmandateuser()) dbuser.setInstitut(sessionform.getInstitut()); else dbuser.setInstitut(user.getInstitut()); dbuser.setIsPVP2Generated(true); dbuser.setLastLogin(DateTimeHelper.getDateTime(new Date())); dbuser.setIsActive(false); dbuser.setIsAdmin(false); dbuser.setIsMandateUser(sessionform.isIsmandateuser()); dbuser.setIsUsernamePasswordAllowed(false); } else dbuser = ConfigurationDBRead.getUserWithID(userID); dbuser.setMail(user.getMail()); dbuser.setPhone(user.getPhone()); dbuser.setIsAdminRequest(true); dbuser.setIsMailAddressVerified(false); dbuser.setUserRequestTokken(Random.nextRandom()); try { ConfigurationDBUtils.saveOrUpdate(dbuser); MailHelper.sendUserMailAddressVerification(dbuser); } catch (MOADatabaseException e) { log.warn("New UserRequest can not be stored in database", e); return Constants.STRUTS_ERROR; } catch (ConfigurationException e) { log.warn("Sending of mailaddress verification mail failed.", e); addActionError(LanguageHelper.getErrorString("error.mail.send")); return Constants.STRUTS_NEWUSER; } finally { session.setAttribute(Constants.SESSION_FORM, null); session.setAttribute(Constants.SESSION_AUTH, null); ConfigurationDBUtils.closeSession(); } addActionMessage(LanguageHelper.getGUIString("webpages.edituser.changemailaddress.verify")); session.invalidate(); return Constants.STRUTS_SUCCESS; } else { log.warn("No SessionForm found"); return Constants.STRUTS_ERROR; } } public String mailAddressVerification() { String userrequesttokken = request.getParameter(Constants.REQUEST_USERREQUESTTOKKEN); if (MiscUtil.isNotEmpty(userrequesttokken)) { userrequesttokken = StringEscapeUtils.escapeHtml(userrequesttokken); try { Long.parseLong(userrequesttokken); } catch (NumberFormatException e) { log.warn("Verificationtokken has no number format."); return Constants.STRUTS_ERROR; } UserDatabase dbuser = ConfigurationDBRead.getNewUserWithTokken(userrequesttokken); if (dbuser != null) { dbuser.setUserRequestTokken(null); dbuser.setIsMailAddressVerified(true); if (dbuser.isIsActive()) dbuser.setIsAdminRequest(false); try { ConfigurationDBUtils.saveOrUpdate(dbuser); int numoas = 0; int numusers = 0; List openOAs = ConfigurationDBRead.getAllNewOnlineApplications(); if (openOAs != null) numoas = openOAs.size(); List openUsers = ConfigurationDBRead.getAllNewUsers(); if (openUsers != null) numusers = openUsers.size(); if (numusers > 0 || numoas > 0) MailHelper.sendAdminMail(numoas, numusers); } catch (MOADatabaseException e) { log.warn("Userinformation can not be stored in Database.", e); addActionError(LanguageHelper.getErrorString("error.mail.verification")); } catch (ConfigurationException e) { log.warn("Send mail to admin failed.", e); } finally { ConfigurationDBUtils.closeSession(); } addActionMessage(LanguageHelper.getGUIString("validation.newuser.mailaddress")); return Constants.STRUTS_SUCCESS; } } return Constants.STRUTS_ERROR; } public String logout() { HttpSession session = request.getSession(); Object authUserObj = session.getAttribute(Constants.SESSION_AUTH); authUser = (AuthenticatedUser) authUserObj; if (session != null) session.invalidate(); try { ConfigurationProvider config = ConfigurationProvider.getInstance(); String ssologout = config.getSSOLogOutURL(); if (MiscUtil.isNotEmpty(ssologout) && authUser != null && authUser.isPVP2Login()) { ssologouturl = ssologout + config.getPublicUrlPreFix(request); return Constants.STRUTS_SSOLOGOUT; } } catch (ConfigurationException e) { log.warn("Configuration can not be loaded.", e); } return Constants.STRUTS_SUCCESS; } public void setServletResponse(HttpServletResponse arg0) { this.response = arg0; } public void setServletRequest(HttpServletRequest arg0) { this.request = arg0; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } /** * @return the authUser */ public AuthenticatedUser getAuthUser() { return authUser; } /** * @return the user */ public UserDatabaseFrom getUser() { return user; } /** * @param user the user to set */ public void setUser(UserDatabaseFrom user) { this.user = user; } /** * @return the ssologouturl */ public String getSsologouturl() { return ssologouturl; } /** * @return the formID */ public String getFormID() { return formID; } /** * @param formID the formID to set */ public void setFormID(String formID) { this.formID = formID; } }