private static Account validateAuthTokenInternal( Provisioning prov, AuthToken at, boolean addToLoggingContext) throws ServiceException { if (prov == null) { prov = Provisioning.getInstance(); } if (at.isExpired()) { throw ServiceException.AUTH_EXPIRED(); } // make sure that the authenticated account is still active and has not been deleted since the // last request String acctId = at.getAccountId(); Account acct = prov.get(AccountBy.id, acctId, at); if (acct == null) { throw ServiceException.AUTH_EXPIRED("account " + acctId + " not found"); } if (addToLoggingContext) { ZimbraLog.addAccountNameToContext(acct.getName()); } if (!acct.checkAuthTokenValidityValue(at)) { throw ServiceException.AUTH_EXPIRED("invalid validity value"); } boolean delegatedAuth = at.isDelegatedAuth(); String acctStatus = acct.getAccountStatus(prov); if (!delegatedAuth && !Provisioning.ACCOUNT_STATUS_ACTIVE.equals(acctStatus)) { throw ServiceException.AUTH_EXPIRED("account not active"); } // if using delegated auth, make sure the "admin" is really an active admin account if (delegatedAuth) { // note that delegated auth allows access unless the account's in maintenance mode if (Provisioning.ACCOUNT_STATUS_MAINTENANCE.equals(acctStatus)) { throw ServiceException.AUTH_EXPIRED("delegated account in MAINTENANCE mode"); } Account admin = prov.get(AccountBy.id, at.getAdminAccountId()); if (admin == null) { throw ServiceException.AUTH_EXPIRED( "delegating account " + at.getAdminAccountId() + " not found"); } boolean isAdmin = AdminAccessControl.isAdequateAdminAccount(admin); if (!isAdmin) { throw ServiceException.PERM_DENIED("not an admin for delegated auth"); } if (!Provisioning.ACCOUNT_STATUS_ACTIVE.equals(admin.getAccountStatus(prov))) { throw ServiceException.AUTH_EXPIRED("delegating account is not active"); } } return acct; }
public Element handle(Element request, Map<String, Object> context) throws ServiceException { ZimbraSoapContext zsc = getZimbraSoapContext(context); Element a = request.getElement(AdminConstants.E_ACCOUNT); String key = a.getAttribute(AdminConstants.A_BY); String value = a.getText(); long lifetime = request.getAttributeLong(AdminConstants.A_DURATION, DEFAULT_AUTH_LIFETIME) * 1000; Provisioning prov = Provisioning.getInstance(); Account account = null; if (key.equals(BY_NAME)) { account = prov.get(AccountBy.name, value, zsc.getAuthToken()); } else if (key.equals(BY_ID)) { account = prov.get(AccountBy.id, value, zsc.getAuthToken()); } else { throw ServiceException.INVALID_REQUEST("unknown value for by: " + key, null); } if (account == null) throw AccountServiceException.NO_SUCH_ACCOUNT(value); checkAdminLoginAsRight(zsc, prov, account); ZimbraLog.security.info( ZimbraLog.encodeAttrs( new String[] { "cmd", "DelegateAuth", "accountId", account.getId(), "accountName", account.getName() })); Element response = zsc.createElement(AdminConstants.DELEGATE_AUTH_RESPONSE); long maxLifetime = account.getTimeInterval( Provisioning.A_zimbraAuthTokenLifetime, DEFAULT_AUTH_LIFETIME * 1000); // take the min of requested lifetime vs maxLifetime long expires = System.currentTimeMillis() + Math.min(lifetime, maxLifetime); String token; Account adminAcct = prov.get(AccountBy.id, zsc.getAuthtokenAccountId(), zsc.getAuthToken()); if (adminAcct == null) throw AccountServiceException.NO_SUCH_ACCOUNT(zsc.getAuthtokenAccountId()); AuthToken at = AuthProvider.getAuthToken(account, expires, false, adminAcct); at.encodeAuthResp(response, true); response.addAttribute(AdminConstants.E_LIFETIME, lifetime, Element.Disposition.CONTENT); return response; }
public Element sendRequestWithNotification(Element request) throws ServiceException { Server server = Provisioning.getInstance() .get(Key.ServerBy.name, OfflineConstants.SYNC_SERVER_PREFIX + getAccountId()); if (server != null) { // when we first add an account, server is still null List<Session> soapSessions = getListeners(Session.Type.SOAP); Session session = null; if (soapSessions.size() == 1) { session = soapSessions.get(0); } else if (soapSessions.size() > 1) { // this occurs if user refreshes web browser (or opens ZD in two different browsers); older // session does not time out so there are now two listening // only the most recent is 'active' for (Session ses : soapSessions) { if (session == null || ses.accessedAfter(session.getLastAccessTime())) { session = ses; } } } if (session != null) { ZAuthToken zat = getAuthToken(); if (zat != null) { AuthToken at = AuthProvider.getAuthToken(OfflineProvisioning.getOfflineInstance().getLocalAccount()); at.setProxyAuthToken(zat.getValue()); ProxyTarget proxy = new ProxyTarget(server, at, getSoapUri()); // zscProxy needs to be for the 'ffffff-' account, but with target of *this* mailbox's // acct // currently UI receives SoapJS in its responses, we ask for that protocol so // notifications are handled correctly ZimbraSoapContext zscIn = new ZimbraSoapContext( at, at.getAccountId(), SoapProtocol.Soap12, SoapProtocol.SoapJS); ZimbraSoapContext zscProxy = new ZimbraSoapContext(zscIn, getAccountId(), session); proxy.setTimeouts(OfflineLC.zdesktop_request_timeout.intValue()); return DocumentHandler.proxyWithNotification(request, proxy, zscProxy, session); } } } return sendRequest(request); }
static void dispatchJspRest(Servlet servlet, UserServletContext context) throws ServiceException, ServletException, IOException { AuthToken auth = null; long expiration = System.currentTimeMillis() + AUTH_EXPIRATION; if (context.basicAuthHappened) { Account acc = context.getAuthAccount(); if (acc instanceof GuestAccount) { auth = AuthToken.getAuthToken( acc.getId(), acc.getName(), null, ((GuestAccount) acc).getDigest(), expiration); } else { auth = AuthProvider.getAuthToken(context.getAuthAccount(), expiration); } } else if (context.cookieAuthHappened) { auth = UserServlet.getAuthTokenFromCookie(context.req, context.resp, true); } else { auth = AuthToken.getAuthToken(GuestAccount.GUID_PUBLIC, null, null, null, expiration); } if (auth != null && context.targetAccount != null && context.targetAccount != context.getAuthAccount()) { auth.setProxyAuthToken( Provisioning.getInstance().getProxyAuthToken(context.targetAccount.getId())); } String authString = null; try { if (auth != null) authString = auth.getEncoded(); } catch (AuthTokenException e) { throw new ServletException("error generating the authToken", e); } Account targetAccount = context.targetAccount; MailItem targetItem = context.target; String uri = (String) context.req.getAttribute("requestedPath"); if (targetItem instanceof Mountpoint && ((Mountpoint) targetItem).getDefaultView() != MailItem.TYPE_APPOINTMENT) { Mountpoint mp = (Mountpoint) targetItem; Provisioning prov = Provisioning.getInstance(); targetAccount = prov.getAccountById(mp.getOwnerId()); Pair<Header[], HttpInputStream> remoteItem = UserServlet.getRemoteResourceAsStream( (auth == null) ? null : auth.toZAuthToken(), mp.getTarget(), context.extraPath); remoteItem.getSecond().close(); String remoteItemId = null; String remoteItemType = null; String remoteItemName = null; String remoteItemPath = null; for (Header h : remoteItem.getFirst()) if (h.getName().compareToIgnoreCase("X-Zimbra-ItemId") == 0) remoteItemId = h.getValue(); else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemType") == 0) remoteItemType = h.getValue(); else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemName") == 0) remoteItemName = h.getValue(); else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemPath") == 0) remoteItemPath = h.getValue(); context.req.setAttribute(ATTR_TARGET_ITEM_ID, remoteItemId); context.req.setAttribute(ATTR_TARGET_ITEM_TYPE, remoteItemType); context.req.setAttribute(ATTR_TARGET_ITEM_NAME, remoteItemName); context.req.setAttribute(ATTR_TARGET_ITEM_PATH, remoteItemPath); context.req.setAttribute(ATTR_TARGET_ITEM_COLOR, mp.getColor()); context.req.setAttribute(ATTR_TARGET_ITEM_VIEW, MailItem.getNameForType(mp.getDefaultView())); targetItem = null; } context.req.setAttribute(ATTR_INTERNAL_DISPATCH, "yes"); context.req.setAttribute(ATTR_REQUEST_URI, uri != null ? uri : context.req.getRequestURI()); context.req.setAttribute(ATTR_AUTH_TOKEN, authString); if (targetAccount != null) { context.req.setAttribute(ATTR_TARGET_ACCOUNT_NAME, targetAccount.getName()); context.req.setAttribute(ATTR_TARGET_ACCOUNT_ID, targetAccount.getId()); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_TIME_ZONE, targetAccount.getAttr(Provisioning.A_zimbraPrefTimeZoneId)); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_SKIN, targetAccount.getAttr(Provisioning.A_zimbraPrefSkin)); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_LOCALE, targetAccount.getAttr(Provisioning.A_zimbraPrefLocale)); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_CALENDAR_FIRST_DAY_OF_WEEK, targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarFirstDayOfWeek)); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_START, targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarDayHourStart)); context.req.setAttribute( ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_END, targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarDayHourEnd)); } if (targetItem != null) { context.req.setAttribute(ATTR_TARGET_ITEM_ID, targetItem.getId()); context.req.setAttribute(ATTR_TARGET_ITEM_TYPE, MailItem.getNameForType(targetItem)); context.req.setAttribute(ATTR_TARGET_ITEM_PATH, targetItem.getPath()); context.req.setAttribute(ATTR_TARGET_ITEM_NAME, targetItem.getName()); context.req.setAttribute(ATTR_TARGET_ITEM_COLOR, targetItem.getColor()); if (targetItem instanceof Folder) context.req.setAttribute( ATTR_TARGET_ITEM_VIEW, MailItem.getNameForType(((Folder) targetItem).getDefaultView())); } String mailUrl = PATH_MAIN_CONTEXT; try { mailUrl = Provisioning.getInstance().getLocalServer().getMailURL(); } catch (Exception e) { } ServletContext targetContext = servlet.getServletConfig().getServletContext().getContext(mailUrl); RequestDispatcher dispatcher = targetContext.getRequestDispatcher(PATH_JSP_REST_PAGE); dispatcher.forward(context.req, context.resp); }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!isHttpReq(request, response)) { return; } HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; AuthToken authToken; try { authToken = getAuthTokenForApp(req, resp, false); } catch (ServiceException se) { ZimbraLog.zimlet.info("can't get authToken: " + se.getMessage()); resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } if (authToken == null) { // error was already sent out return; } boolean isAdminAuth = false; // ZimbraLog.zimlet.info(">>> isAdminAuth: "+isAdminAuth); // get list of allowed zimlets Provisioning prov = Provisioning.getInstance(); List<Zimlet> allowedZimlets = new LinkedList<Zimlet>(); List<Zimlet> allZimlets = new LinkedList<Zimlet>(); try { isAdminAuth = AdminAccessControl.getAdminAccessControl(authToken) .isSufficientAdminForZimletFilterServlet(); // add all available zimlets if (!isAdminAuth) { // zimlets for this account's COS Account account = prov.get(AccountBy.id, authToken.getAccountId(), authToken); for (String zimletName : ZimletUtil.getAvailableZimlets(account).getZimletNamesAsArray()) { Zimlet zimlet = prov.getZimlet(zimletName); if (zimlet == null) continue; if (zimlet.isEnabled()) { allowedZimlets.add(zimlet); } allZimlets.add(zimlet); } } // add the admin zimlets else { allZimlets = prov.listAllZimlets(); Iterator<Zimlet> iter = allZimlets.iterator(); while (iter.hasNext()) { Zimlet zimlet = iter.next(); if (zimlet.isExtension()) { if (zimlet.isEnabled()) { allowedZimlets.add(zimlet); } } } } } catch (ServiceException e) { ZimbraLog.zimlet.info("unable to get list of zimlets"); resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } // order by priority List<Zimlet> zimletList = ZimletUtil.orderZimletsByPriority(allowedZimlets); Set<String> allowedZimletNames = getZimletNames(zimletList); Set<String> allZimletNames = getZimletNames(allZimlets); // get list of zimlets for request Set<String> zimletNames = new LinkedHashSet<String>(); String uri = req.getRequestURI(); boolean isZimletRes = uri.startsWith(ZIMLET_RES_URL_PREFIX); if (isZimletRes) { zimletNames.addAll(allowedZimletNames); } else { Matcher matcher = mPattern.matcher(uri); if (!matcher.matches()) { ZimbraLog.zimlet.info("no zimlet specified in request"); resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } zimletNames.add(matcher.group(1)); } // check access File basedir = new File(LC.zimlet_directory.value()); File devdir = new File(basedir, ZimletUtil.ZIMLET_DEV_DIR); Iterator<String> iter = zimletNames.iterator(); while (iter.hasNext()) { String zimletName = iter.next(); try { File devfile = new File(devdir, zimletName); if (devfile.exists()) { continue; } Zimlet zimlet = prov.getZimlet(zimletName); if (zimlet == null) { ZimbraLog.zimlet.info("no such zimlet: " + zimletName); iter.remove(); allZimlets.remove(zimlet); continue; } if (!allowedZimletNames.contains(zimletName)) { ZimbraLog.zimlet.info( "unauthorized request to zimlet " + zimletName + " from user " + authToken.getAccountId()); iter.remove(); allZimlets.remove(zimlet); continue; } if (zimlet.isExtension() && !isAdminAuth) { // ZimbraLog.zimlet.info("!!!!! removing extension zimlet: "+zimletName); iter.remove(); allZimlets.remove(zimlet); } } catch (ServiceException se) { ZimbraLog.zimlet.info( "service exception to zimlet " + zimletName + " from user " + authToken.getAccountId() + ": " + se.getMessage()); iter.remove(); } } if (!isZimletRes) { Matcher matcher = mPattern.matcher(uri); if (matcher.matches()) { String zimletName = matcher.group(1); if (!zimletNames.contains(zimletName)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } } } // force compilation of template if (uri.endsWith(".template.js")) { Matcher matcher = mPattern.matcher(uri); if (matcher.matches()) { String zimletName = matcher.group(1); String opath = matcher.group(3); String ipath = opath.replaceAll(".js$", ""); boolean isDevZimlet = uri.indexOf("_dev") != -1; File zimletDir = new File(isDevZimlet ? devdir : basedir, zimletName); File ifile = new File(zimletDir, ipath); File ofile = new File(zimletDir, opath); if (!ofile.exists() || (ifile.exists() && ifile.lastModified() > ofile.lastModified())) { String prefix = zimletName + "."; try { TemplateCompiler.compile( zimletDir, zimletDir, prefix, new String[] {ipath}, true, true); } catch (IOException e) { // ignore, let fail } } } } // process request req.setAttribute(ZimletFilter.ALLOWED_ZIMLETS, zimletNames); req.setAttribute(ZimletFilter.ALL_ZIMLETS, allZimletNames); chain.doFilter(req, resp); }