use of com.tremolosecurity.proxy.auth.AuthInfo in project OpenUnison by TremoloSecurity.
the class ScaleMain method runReport.
private void runReport(final HttpFilterRequest request, final HttpFilterResponse response, final Gson gson) throws UnsupportedEncodingException, IOException, MalformedURLException, ProvisioningException, SQLException {
String name = URLDecoder.decode(request.getRequestURI().substring(request.getRequestURI().lastIndexOf('/') + 1), "UTF-8");
ReportType reportToRun = null;
for (ReportType report : GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getReports().getReport()) {
if (report.getName().equalsIgnoreCase(name)) {
reportToRun = report;
break;
}
}
if (reportToRun == null) {
response.setStatus(404);
ScaleError error = new ScaleError();
error.getErrors().add("Report not found");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
} else {
HashSet<String> allowedOrgs = new HashSet<String>();
final AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
OrgType ot = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getOrg();
AzSys az = new AzSys();
this.checkOrg(allowedOrgs, ot, az, userData, request.getSession());
if (allowedOrgs.contains(reportToRun.getOrgID())) {
Connection db = null;
final ReportType reportToRunUse = reportToRun;
try {
Session session = GlobalEntries.getGlobalEntries().getConfigManager().getProvisioningEngine().getHibernateSessionFactory().openSession();
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
try {
generateReport(request, response, gson, reportToRunUse, userData, connection);
} catch (IOException e) {
throw new SQLException("Could not run reports", e);
}
}
});
} finally {
}
} else {
response.setStatus(401);
ScaleError error = new ScaleError();
error.getErrors().add("Unauthorized");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
}
}
}
use of com.tremolosecurity.proxy.auth.AuthInfo in project OpenUnison by TremoloSecurity.
the class ScaleMain method loadWorkflows.
private void loadWorkflows(HttpFilterRequest request, HttpFilterResponse response, Gson gson) throws Exception {
String orgid = request.getRequestURI().substring(request.getRequestURI().lastIndexOf('/') + 1);
ConfigManager cfgMgr = GlobalEntries.getGlobalEntries().getConfigManager();
HashSet<String> allowedOrgs = new HashSet<String>();
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
OrgType ot = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getOrg();
AzSys az = new AzSys();
this.checkOrg(allowedOrgs, ot, az, userData, request.getSession());
if (!allowedOrgs.contains(orgid)) {
response.setStatus(401);
response.setContentType("application/json");
ScaleError error = new ScaleError();
error.getErrors().add("Unauthorized");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
} else {
List<WorkflowType> wfs = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getWorkflows().getWorkflow();
ArrayList<WFDescription> workflows = new ArrayList<WFDescription>();
for (WorkflowType wf : wfs) {
if (wf.isInList() != null && wf.isInList().booleanValue()) {
if (wf.getOrgid() == null || wf.getOrgid().equalsIgnoreCase(orgid)) {
if (wf.getDynamicConfiguration() != null && wf.getDynamicConfiguration().isDynamic()) {
HashMap<String, Attribute> params = new HashMap<String, Attribute>();
if (wf.getDynamicConfiguration().getParam() != null) {
for (ParamType p : wf.getDynamicConfiguration().getParam()) {
Attribute attr = params.get(p.getName());
if (attr == null) {
attr = new Attribute(p.getName());
params.put(p.getName(), attr);
}
attr.getValues().add(p.getValue());
}
}
DynamicWorkflow dwf = (DynamicWorkflow) Class.forName(wf.getDynamicConfiguration().getClassName()).newInstance();
List<Map<String, String>> wfParams = dwf.generateWorkflows(wf, cfgMgr, params, userData);
StringBuffer b = new StringBuffer();
b.append('/').append(URLEncoder.encode(wf.getName(), "UTF-8"));
String uri = b.toString();
for (Map<String, String> wfParamSet : wfParams) {
DateTime now = new DateTime();
DateTime expires = now.plusHours(1);
LastMile lm = new LastMile(uri, now, expires, 0, "");
for (String key : wfParamSet.keySet()) {
String val = wfParamSet.get(key);
Attribute attr = new Attribute(key, val);
lm.getAttributes().add(attr);
}
WFDescription desc = new WFDescription();
desc.setUuid(UUID.randomUUID().toString());
desc.setName(wf.getName());
ST st = new ST(wf.getLabel(), '$', '$');
for (String key : wfParamSet.keySet()) {
st.add(key.replaceAll("[.]", "_"), wfParamSet.get(key));
}
desc.setLabel(st.render());
st = new ST(wf.getDescription(), '$', '$');
for (String key : wfParamSet.keySet()) {
st.add(key.replaceAll("[.]", "_"), wfParamSet.get(key));
}
desc.setDescription(st.render());
desc.setEncryptedParams(lm.generateLastMileToken(cfgMgr.getSecretKey(cfgMgr.getCfg().getProvisioning().getApprovalDB().getEncryptionKey())));
workflows.add(desc);
}
} else {
WFDescription desc = new WFDescription();
desc.setUuid(UUID.randomUUID().toString());
desc.setName(wf.getName());
desc.setLabel(wf.getLabel());
desc.setDescription(wf.getDescription());
workflows.add(desc);
}
}
}
}
ScaleJSUtils.addCacheHeaders(response);
response.setContentType("application/json");
response.getWriter().println(gson.toJson(workflows).trim());
response.getWriter().flush();
}
}
use of com.tremolosecurity.proxy.auth.AuthInfo in project OpenUnison by TremoloSecurity.
the class ScaleMain method loadReports.
private void loadReports(HttpFilterRequest request, HttpFilterResponse response, Gson gson) throws MalformedURLException, ProvisioningException, IOException {
String orgid = request.getRequestURI().substring(request.getRequestURI().lastIndexOf('/') + 1);
ConfigManager cfgMgr = GlobalEntries.getGlobalEntries().getConfigManager();
HashSet<String> allowedOrgs = new HashSet<String>();
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
OrgType ot = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getOrg();
AzSys az = new AzSys();
this.checkOrg(allowedOrgs, ot, az, userData, request.getSession());
if (!allowedOrgs.contains(orgid)) {
response.setStatus(401);
response.setContentType("application/json");
ScaleError error = new ScaleError();
error.getErrors().add("Unauthorized");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
} else {
ReportsType reports = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getReports();
ReportsList reportsList = new ReportsList();
reportsList.setReports(new ArrayList<ReportInformation>());
if (reports != null && reports.getReport() != null) {
for (ReportType report : reports.getReport()) {
if (report.getOrgID().equals(orgid)) {
ReportInformation ri = new ReportInformation();
ri.setName(report.getName());
ri.setDescription(report.getDescription());
ri.setOrgID(report.getOrgID());
ri.setParameters(new ArrayList<String>());
ri.getParameters().addAll(report.getParamater());
ri.getParameters().remove("currentUser");
reportsList.getReports().add(ri);
}
}
}
response.setContentType("application/json");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().println(gson.toJson(reportsList).trim());
response.getWriter().flush();
}
}
use of com.tremolosecurity.proxy.auth.AuthInfo in project OpenUnison by TremoloSecurity.
the class ScaleMain method doFilter.
@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");
try {
if (request.getRequestURI().endsWith("/main/config")) {
if (scaleConfig.getUiDecisions() != null) {
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
Set<String> allowedAttrs = this.scaleConfig.getUiDecisions().availableAttributes(userData, request.getServletRequest());
ScaleConfig local = new ScaleConfig(this.scaleConfig);
if (allowedAttrs != null) {
for (String attrName : this.scaleConfig.getAttributes().keySet()) {
if (!allowedAttrs.contains(attrName)) {
local.getAttributes().remove(attrName);
}
}
}
local.setCanEditUser(this.scaleConfig.getUiDecisions().canEditUser(userData, request.getServletRequest()));
ScaleJSUtils.addCacheHeaders(response);
response.setContentType("application/json");
response.getWriter().println(gson.toJson(local).trim());
} else {
ScaleJSUtils.addCacheHeaders(response);
response.setContentType("application/json");
response.getWriter().println(gson.toJson(scaleConfig).trim());
}
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().endsWith("/main/user")) {
lookupUser(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("PUT") && request.getRequestURI().endsWith("/main/user")) {
saveUser(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().endsWith("/main/orgs")) {
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
AzSys az = new AzSys();
OrgType ot = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getOrg();
Organization org = new Organization();
copyOrg(org, ot, az, userData);
ScaleJSUtils.addCacheHeaders(response);
response.setContentType("application/json");
response.getWriter().println(gson.toJson(org).trim());
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/workflows/org/")) {
loadWorkflows(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/workflows/candelegate")) {
try {
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
OrgType ot = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getOrg();
AzSys az = new AzSys();
HashSet<String> allowedOrgs = new HashSet<String>();
this.checkOrg(allowedOrgs, ot, az, userData, request.getSession());
String workflowName = request.getParameter("workflowName").getValues().get(0);
// need to check org
String orgid = null;
for (WorkflowType wf : GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getWorkflows().getWorkflow()) {
if (wf.getName().equals(workflowName)) {
orgid = wf.getOrgid();
break;
}
}
PreCheckResponse preCheckResp = new PreCheckResponse();
if (request.getParameter("uuid") != null) {
preCheckResp.setUuid(request.getParameter("uuid").getValues().get(0));
}
checkPreCheck(request, userData, allowedOrgs, workflowName, orgid, preCheckResp);
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(preCheckResp).trim());
response.getWriter().flush();
} catch (Throwable t) {
logger.error("Could not check for preapproval status", t);
response.setStatus(500);
response.setContentType("application/json");
ScaleJSUtils.addCacheHeaders(response);
ScaleError error = new ScaleError();
error.getErrors().add("Unable to check");
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
}
} else if (request.getMethod().equalsIgnoreCase("PUT") && request.getRequestURI().endsWith("/main/workflows")) {
executeWorkflows(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().endsWith("/main/approvals")) {
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
String uid = userData.getAttribs().get(this.scaleConfig.getUidAttributeName()).getValues().get(0);
response.setContentType("application/json");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().println(gson.toJson(ServiceActions.listOpenApprovals(uid, this.scaleConfig.getDisplayNameAttribute(), GlobalEntries.getGlobalEntries().getConfigManager())).trim());
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/approvals/")) {
loadApproval(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("PUT") && request.getRequestURI().contains("/main/approvals/")) {
int approvalID = Integer.parseInt(request.getRequestURI().substring(request.getRequestURI().lastIndexOf('/') + 1));
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
String uid = userData.getAttribs().get(this.scaleConfig.getUidAttributeName()).getValues().get(0);
boolean ok = false;
ApprovalSummaries summaries = ServiceActions.listOpenApprovals(uid, this.scaleConfig.getDisplayNameAttribute(), GlobalEntries.getGlobalEntries().getConfigManager());
for (ApprovalSummary as : summaries.getApprovals()) {
if (as.getApproval() == approvalID) {
ok = true;
}
}
if (!ok) {
response.setStatus(401);
response.setContentType("application/json");
ScaleJSUtils.addCacheHeaders(response);
ScaleError error = new ScaleError();
error.getErrors().add("Unauthorized");
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
} else {
ScaleApprovalData approvalData = gson.fromJson(new String((byte[]) request.getAttribute(ProxySys.MSG_BODY)), ScaleApprovalData.class);
try {
String approval = approvalData.getReason().trim();
if (approval.length() > 255) {
logger.warn("approval justification greater then 255 characters");
approval = approval.substring(0, 255);
}
GlobalEntries.getGlobalEntries().getConfigManager().getProvisioningEngine().doApproval(approvalID, uid, approvalData.isApproved(), approval);
} catch (Exception e) {
logger.error("Could not execute approval", e);
response.setStatus(500);
ScaleError error = new ScaleError();
error.getErrors().add("There was a problem completeding your request, please contact your system administrator");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
}
}
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/reports/org/")) {
loadReports(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/reports/excel/")) {
exportToExcel(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/reports/")) {
runReport(request, response, gson);
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().endsWith("/main/urls")) {
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
AzSys az = new AzSys();
PortalUrlsType pt = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getPortal();
PortalURLs urls = new PortalURLs();
if (pt != null && pt.getUrls() != null) {
for (PortalUrlType url : pt.getUrls()) {
if (url.getAzRules() != null && url.getAzRules().getRule().size() > 0) {
ArrayList<AzRule> rules = new ArrayList<AzRule>();
for (AzRuleType art : url.getAzRules().getRule()) {
rules.add(new AzRule(art.getScope(), art.getConstraint(), art.getClassName(), GlobalEntries.getGlobalEntries().getConfigManager(), null));
}
if (!az.checkRules(userData, GlobalEntries.getGlobalEntries().getConfigManager(), rules, request.getSession(), this.appType, new HashMap<String, Object>())) {
continue;
}
}
PortalURL purl = new PortalURL();
purl.setName(url.getName());
purl.setLabel(url.getLabel());
purl.setOrg(url.getOrg());
purl.setUrl(url.getUrl());
purl.setIcon(url.getIcon());
urls.getUrls().add(purl);
}
}
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(urls.getUrls()).trim());
response.getWriter().flush();
} else if (request.getMethod().equalsIgnoreCase("GET") && request.getRequestURI().contains("/main/urls/org")) {
String id = URLDecoder.decode(request.getRequestURI().substring(request.getRequestURI().lastIndexOf('/') + 1), "UTF-8");
AuthInfo userData = ((AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
AzSys az = new AzSys();
PortalUrlsType pt = GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getProvisioning().getPortal();
PortalURLs urls = new PortalURLs();
for (PortalUrlType url : pt.getUrls()) {
if (url.getOrg().equalsIgnoreCase(id)) {
if (url.getAzRules() != null && url.getAzRules().getRule().size() > 0) {
ArrayList<AzRule> rules = new ArrayList<AzRule>();
for (AzRuleType art : url.getAzRules().getRule()) {
rules.add(new AzRule(art.getScope(), art.getConstraint(), art.getClassName(), GlobalEntries.getGlobalEntries().getConfigManager(), null));
}
if (!az.checkRules(userData, GlobalEntries.getGlobalEntries().getConfigManager(), rules, request.getSession(), this.appType, new HashMap<String, Object>())) {
continue;
}
}
PortalURL purl = new PortalURL();
purl.setName(url.getName());
purl.setLabel(url.getLabel());
purl.setOrg(url.getOrg());
purl.setUrl(url.getUrl());
purl.setIcon(url.getIcon());
urls.getUrls().add(purl);
}
}
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(urls.getUrls()).trim());
response.getWriter().flush();
} else {
response.setStatus(500);
ScaleError error = new ScaleError();
error.getErrors().add("Operation not supported");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
}
} catch (Throwable t) {
logger.error("Could not execute request", t);
response.setStatus(500);
ScaleError error = new ScaleError();
error.getErrors().add("Operation not supported");
ScaleJSUtils.addCacheHeaders(response);
response.getWriter().print(gson.toJson(error).trim());
response.getWriter().flush();
}
}
use of com.tremolosecurity.proxy.auth.AuthInfo in project OpenUnison by TremoloSecurity.
the class ScaleJSOperator method lookupUser.
private void lookupUser(HttpFilterRequest request, HttpFilterResponse response, Gson gson) throws Exception, LDAPException, IOException {
if (this.scaleMainConfig == null) {
UrlHolder holder = GlobalEntries.getGlobalEntries().getConfigManager().findURL(this.scaleMainURL);
for (HttpFilter filter : holder.getFilterChain()) {
if (filter instanceof ScaleMain) {
ScaleMain scaleMain = (ScaleMain) filter;
this.scaleMainConfig = scaleMain.scaleConfig;
}
}
}
String dn = request.getParameter("dn").getValues().get(0);
FilterBuilder baseFilter = (FilterBuilder) request.getAttribute("ops.search.filter");
String filter = "(objectClass=*)";
if (baseFilter != null) {
filter = baseFilter.toString();
}
LDAPSearchResults res = GlobalEntries.getGlobalEntries().getConfigManager().getMyVD().search(dn, 0, filter, new ArrayList<String>());
if (!res.hasMore()) {
throw new Exception("Could not locate user '" + dn + "'");
}
LDAPEntry entry = res.next();
AuthInfo userData = new AuthInfo();
userData.setUserDN(entry.getDN());
LDAPAttributeSet attrs = entry.getAttributeSet();
for (Object obj : attrs) {
LDAPAttribute attr = (LDAPAttribute) obj;
Attribute attrib = new Attribute(attr.getName());
String[] vals = attr.getStringValueArray();
for (String val : vals) {
attrib.getValues().add(val);
}
userData.getAttribs().put(attrib.getName(), attrib);
}
Set<String> allowedAttrs = null;
if (scaleMainConfig.getUiDecisions() != null) {
allowedAttrs = this.scaleMainConfig.getUiDecisions().availableAttributes(userData, request.getServletRequest());
}
OpsUserData userToSend = new OpsUserData();
userToSend.setDn(userData.getUserDN());
for (String attrName : this.scaleMainConfig.getUserAttributeList()) {
if (allowedAttrs == null || allowedAttrs.contains(attrName)) {
Attribute attr = new Attribute(attrName);
Attribute fromUser = userData.getAttribs().get(attrName);
if (fromUser != null) {
attr.getValues().addAll(fromUser.getValues());
if (attrName.equalsIgnoreCase(this.scaleMainConfig.getUidAttributeName())) {
userToSend.setUid(fromUser.getValues().get(0));
}
}
userToSend.getAttributes().add(attr);
}
}
if (this.scaleMainConfig.getRoleAttribute() != null && !this.scaleMainConfig.getRoleAttribute().isEmpty()) {
Attribute fromUser = userData.getAttribs().get(this.scaleMainConfig.getRoleAttribute());
Attribute attr = new Attribute(this.scaleMainConfig.getRoleAttribute());
if (fromUser != null) {
attr.getValues().addAll(fromUser.getValues());
userToSend.getGroups().clear();
userToSend.getGroups().addAll(fromUser.getValues());
}
userToSend.getAttributes().add(attr);
}
ArrayList<String> attrNames = new ArrayList<String>();
attrNames.add("cn");
attrNames.add(GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getGroupMemberAttribute());
res = GlobalEntries.getGlobalEntries().getConfigManager().getMyVD().search(GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getLdapRoot(), 2, equal(GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getGroupMemberAttribute(), dn).toString(), attrNames);
net.sourceforge.myvd.types.Filter ldapFiltertoCheck = new net.sourceforge.myvd.types.Filter(equal(GlobalEntries.getGlobalEntries().getConfigManager().getCfg().getGroupMemberAttribute(), dn).toString());
while (res.hasMore()) {
entry = res.next();
if (ldapFiltertoCheck.getRoot().checkEntry(entry)) {
LDAPAttribute la = entry.getAttribute("cn");
if (la != null) {
String val = la.getStringValue();
if (!userToSend.getGroups().contains(val)) {
userToSend.getGroups().add(val);
}
}
}
}
if (scaleMainConfig.getUiDecisions() != null) {
Set<String> smAllowedAttrs = this.scaleMainConfig.getUiDecisions().availableAttributes(userData, request.getServletRequest());
ScaleConfig local = new ScaleConfig(this.scaleMainConfig);
if (smAllowedAttrs != null) {
for (String attrName : this.scaleMainConfig.getAttributes().keySet()) {
if (!smAllowedAttrs.contains(attrName)) {
local.getAttributes().remove(attrName);
}
}
}
userToSend.setMetaData(local.getAttributes());
userToSend.setCanEditUser(this.scaleMainConfig.getUiDecisions().canEditUser(userData, request.getServletRequest()));
} else {
userToSend.setMetaData(scaleMainConfig.getAttributes());
userToSend.setCanEditUser(scaleMainConfig.isCanEditUser());
}
ScaleJSUtils.addCacheHeaders(response);
response.setContentType("application/json");
response.getWriter().println(gson.toJson(userToSend).trim());
}
Aggregations