Java tutorial
/******************************************************************************* * Copyright 2016 Tremolo Security, Inc. * 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 com.tremolosecurity.scalejs.register.ws; import static org.apache.directory.ldap.client.api.search.FilterBuilder.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import org.apache.http.NameValuePair; import org.apache.http.client.config.CookieSpecs; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import com.google.gson.Gson; import com.novell.ldap.LDAPSearchResults; import com.tremolosecurity.provisioning.core.ProvisioningException; import com.tremolosecurity.provisioning.core.User; import com.tremolosecurity.provisioning.service.util.TremoloUser; import com.tremolosecurity.provisioning.service.util.WFCall; import com.tremolosecurity.provisioning.tasks.Approval; import com.tremolosecurity.provisioning.workflow.ApprovalData; import com.tremolosecurity.provisioning.workflow.ExecuteWorkflow; import com.tremolosecurity.proxy.ProxySys; import com.tremolosecurity.proxy.auth.AuthController; import com.tremolosecurity.proxy.auth.AuthInfo; import com.tremolosecurity.proxy.filter.HttpFilter; import com.tremolosecurity.proxy.filter.HttpFilterChain; import com.tremolosecurity.proxy.filter.HttpFilterConfig; import com.tremolosecurity.proxy.filter.HttpFilterRequest; import com.tremolosecurity.proxy.filter.HttpFilterResponse; import com.tremolosecurity.proxy.util.ProxyConstants; import com.tremolosecurity.saml.Attribute; import com.tremolosecurity.scalejs.cfg.ScaleAttribute; import com.tremolosecurity.scalejs.data.ScaleError; import com.tremolosecurity.scalejs.register.cfg.ScaleJSRegisterConfig; import com.tremolosecurity.scalejs.register.data.NewUserRequest; import com.tremolosecurity.scalejs.register.data.ReCaptchaResponse; import com.tremolosecurity.scalejs.register.data.SubmitResponse; import com.tremolosecurity.scalejs.register.sdk.CreateRegisterUser; import com.tremolosecurity.scalejs.util.ScaleJSUtils; import com.tremolosecurity.server.GlobalEntries; import com.tremolosecurity.util.NVP; public class ScaleRegister implements HttpFilter { static org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager .getLogger(ScaleRegister.class.getName()); private ScaleJSRegisterConfig scaleConfig; private CreateRegisterUser cru; @Override public void doFilter(HttpFilterRequest request, HttpFilterResponse response, HttpFilterChain chain) throws Exception { Gson gson = new Gson(); request.getServletRequest().setAttribute("com.tremolosecurity.unison.proxy.noRedirectOnError", "com.tremolosecurity.unison.proxy.noRedirectOnError"); if (request.getRequestURI().endsWith("/register/config")) { response.setContentType("application/json"); ScaleJSUtils.addCacheHeaders(response); response.getWriter().println(gson.toJson(scaleConfig).trim()); } else if (request.getRequestURI().endsWith("/register/submit")) { ScaleError errors = new ScaleError(); String json = new String((byte[]) request.getAttribute(ProxySys.MSG_BODY)); NewUserRequest newUser = gson.fromJson(json, NewUserRequest.class); if (scaleConfig.isRequireReCaptcha()) { if (newUser.getReCaptchaCode() == null || newUser.getReCaptchaCode().isEmpty()) { errors.getErrors().add("Please verify you are not a robot"); } else { BasicHttpClientConnectionManager bhcm = new BasicHttpClientConnectionManager( GlobalEntries.getGlobalEntries().getConfigManager().getHttpClientSocketRegistry()); RequestConfig rc = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build(); CloseableHttpClient http = HttpClients.custom().setConnectionManager(bhcm) .setDefaultRequestConfig(rc).build(); HttpPost httppost = new HttpPost("https://www.google.com/recaptcha/api/siteverify"); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("secret", scaleConfig.getRcSecretKey())); formparams.add(new BasicNameValuePair("response", newUser.getReCaptchaCode())); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); httppost.setEntity(entity); CloseableHttpResponse resp = http.execute(httppost); ReCaptchaResponse res = gson.fromJson(EntityUtils.toString(resp.getEntity()), ReCaptchaResponse.class); if (!res.isSuccess()) { errors.getErrors().add("Human validation failed"); } http.close(); bhcm.close(); } } if (scaleConfig.isRequireTermsAndConditions() && !newUser.isCheckedTermsAndConditions()) { errors.getErrors().add("You must accept the terms and conditions to register"); } if (this.scaleConfig.isRequireReason() && (newUser.getReason() == null || newUser.getReason().isEmpty())) { errors.getErrors().add("Reason is required"); } if (this.scaleConfig.isPreSetPassword()) { if (newUser.getPassword() == null || newUser.getPassword().isEmpty()) { errors.getErrors().add("Password is required"); } else if (!newUser.getPassword().equals(newUser.getPassword2())) { errors.getErrors().add("Passwords must match"); } } for (String attributeName : this.scaleConfig.getAttributes().keySet()) { String value = newUser.getAttributes().get(attributeName); if (this.scaleConfig.getAttributes().get(attributeName) == null) { errors.getErrors().add("Invalid attribute : '" + attributeName + "'"); } if (this.scaleConfig.getAttributes().get(attributeName).isReadOnly()) { errors.getErrors().add("Attribute is read only : '" + this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + "'"); } if (this.scaleConfig.getAttributes().get(attributeName).isRequired() && (value == null || value.length() == 0)) { errors.getErrors().add("Attribute is required : '" + this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + "'"); } if (this.scaleConfig.getAttributes().get(attributeName).getMinChars() > 0 && this.scaleConfig.getAttributes().get(attributeName).getMinChars() < value.length()) { errors.getErrors().add(this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + " must have at least " + this.scaleConfig.getAttributes().get(attributeName).getMinChars() + " characters"); } if (this.scaleConfig.getAttributes().get(attributeName).getMaxChars() > 0 && this.scaleConfig.getAttributes().get(attributeName).getMaxChars() > value.length()) { errors.getErrors().add(this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + " must have at most " + this.scaleConfig.getAttributes().get(attributeName).getMaxChars() + " characters"); } if (this.scaleConfig.getAttributes().get(attributeName).getType().equalsIgnoreCase("list")) { boolean found = false; for (NVP nvp : this.scaleConfig.getAttributes().get(attributeName).getValues()) { if (nvp.getValue().equalsIgnoreCase(value)) { found = true; } } if (!found) { errors.getErrors().add(this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + " has an invalid value"); } } if (this.scaleConfig.getAttributes().get(attributeName).getPattern() != null) { boolean ok = true; try { Matcher m = this.scaleConfig.getAttributes().get(attributeName).getPattern().matcher(value); if (m == null || !m.matches()) { ok = false; } } catch (Exception e) { ok = false; } if (!ok) { errors.getErrors().add("Attribute value not valid : '" + this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + "' - " + this.scaleConfig.getAttributes().get(attributeName).getRegExFailedMsg()); } } if (this.scaleConfig.getAttributes().get(attributeName).isUnique()) { String filter = equal(attributeName, value).toString(); LDAPSearchResults res = GlobalEntries.getGlobalEntries().getConfigManager().getMyVD().search( GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getLdapRoot(), 2, filter, new ArrayList<String>()); if (res.hasMore()) { errors.getErrors().add(this.scaleConfig.getAttributes().get(attributeName).getDisplayName() + " is not available"); } while (res.hasMore()) res.next(); } } WFCall wfcall = null; String wfName = this.scaleConfig.getWorkflowName(); if (errors.getErrors().isEmpty()) { if (scaleConfig.isUseCustomSubmission()) { AuthInfo userData = ((AuthController) request.getSession() .getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo(); wfName = cru.createTremoloUser(newUser, errors.getErrors(), userData); } } if (errors.getErrors().isEmpty()) { TremoloUser user = new TremoloUser(); AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)) .getAuthInfo(); if (this.scaleConfig.isSubmitLoggedInUser()) { user.setUid( userData.getAttribs().get(this.scaleConfig.getUidAttributeName()).getValues().get(0)); user.getAttributes().add(new Attribute(this.scaleConfig.getUidAttributeName(), userData.getAttribs().get(this.scaleConfig.getUidAttributeName()).getValues().get(0))); } else { user.setUid(newUser.getAttributes().get(this.scaleConfig.getUidAttributeName())); } for (String attrName : newUser.getAttributes().keySet()) { user.getAttributes().add(new Attribute(attrName, newUser.getAttributes().get(attrName))); } if (this.scaleConfig.isPreSetPassword()) { user.setUserPassword(newUser.getPassword()); } wfcall = new WFCall(); wfcall.setUidAttributeName(this.scaleConfig.getUidAttributeName()); wfcall.setReason(newUser.getReason()); wfcall.setName(wfName); wfcall.setUser(user); HashMap<String, Object> params = new HashMap<String, Object>(); wfcall.setRequestParams(params); if (userData.getAuthLevel() != 0 && !this.scaleConfig.isSubmitLoggedInUser()) { wfcall.setRequestor( userData.getAttribs() .get(GlobalEntries.getGlobalEntries().getConfigManager().getCfg() .getProvisioning().getApprovalDB().getUserIdAttribute()) .getValues().get(0)); wfcall.getRequestParams().put(Approval.SEND_NOTIFICATION, "false"); wfcall.getRequestParams().put(Approval.REASON, newUser.getReason()); wfcall.getRequestParams().put(Approval.IMMEDIATE_ACTION, "true"); } ExecuteWorkflow exec = new ExecuteWorkflow(); try { exec.execute(wfcall, GlobalEntries.getGlobalEntries().getConfigManager()); } catch (Exception e) { throw new ProvisioningException("Could not complete registration", e); } SubmitResponse res = new SubmitResponse(); res.setAddNewUsers(userData.getAuthLevel() != 0); ScaleJSUtils.addCacheHeaders(response); response.getWriter().print(gson.toJson(res)); response.getWriter().flush(); } else { response.setStatus(500); ScaleJSUtils.addCacheHeaders(response); response.getWriter().print(gson.toJson(errors).trim()); response.getWriter().flush(); } } else { response.setStatus(500); ScaleJSUtils.addCacheHeaders(response); ScaleError error = new ScaleError(); error.getErrors().add("Operation not supported"); response.getWriter().print(gson.toJson(error).trim()); response.getWriter().flush(); } } @Override public void filterResponseText(HttpFilterRequest request, HttpFilterResponse response, HttpFilterChain chain, StringBuffer data) throws Exception { // TODO Auto-generated method stub } @Override public void filterResponseBinary(HttpFilterRequest request, HttpFilterResponse response, HttpFilterChain chain, byte[] data, int length) throws Exception { // TODO Auto-generated method stub } private String loadAttributeValue(String name, String label, HttpFilterConfig config) throws Exception { Attribute attr = config.getAttribute(name); if (attr == null) { throw new Exception(label + " not found"); } String val = attr.getValues().get(0); logger.info(label + ": '" + val + "'"); return val; } private String loadOptionalAttributeValue(String name, String label, HttpFilterConfig config) throws Exception { Attribute attr = config.getAttribute(name); if (attr == null) { logger.warn(label + " not found"); return null; } String val = attr.getValues().get(0); logger.info(label + ": '" + val + "'"); return val; } @Override public void initFilter(HttpFilterConfig config) throws Exception { this.scaleConfig = new ScaleJSRegisterConfig(); scaleConfig.getFrontPage().setTitle(this.loadAttributeValue("frontPage.title", "Front Page Title", config)); scaleConfig.getFrontPage().setText(this.loadAttributeValue("frontPage.text", "Front Page Text", config)); scaleConfig.setHomeURL(this.loadAttributeValue("homeURL", "Home URL", config)); scaleConfig.setLogoutURL(this.loadAttributeValue("logoutURL", "Logout URL", config)); scaleConfig.setUidAttributeName(this.loadAttributeValue("uidAttributeName", "UID Attribute Name", config)); scaleConfig.setWorkflowName(this.loadAttributeValue("workflowName", "Workflow Name", config)); String val = this.loadOptionalAttributeValue("requireReason", "Require Reason", config); scaleConfig.setRequireReason(val != null && val.equals("true")); val = this.loadOptionalAttributeValue("preSetPassword", "Pre-Set Password", config); scaleConfig.setPreSetPassword(val != null && val.equals("true")); Attribute attr = config.getAttribute("attributeNames"); if (attr == null) { throw new Exception("Attribute names not found"); } val = this.loadOptionalAttributeValue("requireReCaptcha", "ReCaptcha Required", config); if (val == null) { val = "false"; } scaleConfig.setRequireReCaptcha(val.equalsIgnoreCase("true")); if (scaleConfig.isRequireReCaptcha()) { scaleConfig.setRcSiteKey(this.loadAttributeValue("rcSiteKey", "ReCaptcha Site Key", config)); scaleConfig.setRcSecretKey(this.loadAttributeValue("rcSecret", "ReCaptcha Secret Key", config)); } val = this.loadOptionalAttributeValue("requireTermsAndConditions", "Require Terms and Conditions", config); if (val == null) { val = "false"; } scaleConfig.setRequireTermsAndConditions(val.equalsIgnoreCase("true")); if (scaleConfig.isRequireTermsAndConditions()) { scaleConfig.setTermsAndConditionsText( this.loadAttributeValue("termsAndConditionsText", "Terms and Conditions", config)); } for (String attributeName : attr.getValues()) { scaleConfig.getAttributeNameList().add(attributeName); ScaleAttribute scaleAttr = new ScaleAttribute(); scaleAttr.setName(attributeName); scaleAttr.setDisplayName(this.loadAttributeValue(attributeName + ".displayName", attributeName + " Display Name", config)); scaleAttr.setReadOnly(false); scaleAttr.setRequired(true); val = this.loadOptionalAttributeValue(attributeName + ".required", attributeName + " Required", config); if (val != null) { scaleAttr.setRequired(val.equalsIgnoreCase("true")); } val = this.loadOptionalAttributeValue(attributeName + ".regEx", attributeName + " Reg Ex", config); if (val != null) { scaleAttr.setRegEx(val); } val = this.loadOptionalAttributeValue(attributeName + ".regExFailedMsg", attributeName + " Reg Ex Failed Message", config); if (val != null) { scaleAttr.setRegExFailedMsg(val); } val = this.loadOptionalAttributeValue(attributeName + ".minChars", attributeName + " Minimum Characters", config); if (val != null) { scaleAttr.setMinChars(Integer.parseInt(val)); } val = this.loadOptionalAttributeValue(attributeName + ".mxnChars", attributeName + " Maximum Characters", config); if (val != null) { scaleAttr.setMaxChars(Integer.parseInt(val)); } val = this.loadOptionalAttributeValue(attributeName + ".unique", attributeName + " Attribute Value Must Be Unique", config); if (val != null) { scaleAttr.setUnique(val.equalsIgnoreCase("true")); } val = this.loadOptionalAttributeValue(attributeName + ".type", attributeName + " Attribute Type", config); if (val != null) { scaleAttr.setType(val); } Attribute attrVals = config.getAttribute(attributeName + ".values"); if (attrVals != null) { for (String attrVal : attrVals.getValues()) { String valLabel = attrVal.substring(0, attrVal.indexOf('=')); String valValue = attrVal.substring(attrVal.indexOf('=') + 1); scaleAttr.getValues().add(new NVP(valLabel, valValue)); } } scaleConfig.getAttributes().put(attributeName, scaleAttr); } val = loadOptionalAttributeValue("useCallWorkflowClass", "Use Custom Submission", config); if (val == null) { val = "false"; } scaleConfig.setUseCustomSubmission(val.equalsIgnoreCase("true")); val = loadOptionalAttributeValue("submitLoggedInUser", "Submit logged in user as subject", config); if (val == null) { val = "false"; } scaleConfig.setSubmitLoggedInUser(val.equalsIgnoreCase("true")); if (scaleConfig.isUseCustomSubmission()) { scaleConfig.setCustomSubmissionClassName( this.loadAttributeValue("callWorkflowClassName", "Custom Submission Class", config)); Attribute tattr = config.getAttribute("callWorkflowInit"); scaleConfig.setCustomSubmissionConfig(new HashMap<String, Attribute>()); if (tattr != null) { for (String value : tattr.getValues()) { String n = value.substring(0, value.indexOf('=')); String v = value.substring(value.indexOf('=') + 1); Attribute tmpa = scaleConfig.getCustomSubmissionConfig().get(n); if (tmpa == null) { tmpa = new Attribute(n); scaleConfig.getCustomSubmissionConfig().put(n, tmpa); } tmpa.getValues().add(v); } } this.cru = (CreateRegisterUser) Class.forName(scaleConfig.getCustomSubmissionClassName()).newInstance(); this.cru.init(this.scaleConfig); } } }