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;
  }
Example #2
0
  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;
  }
Example #3
0
 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);
 }
Example #4
0
  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);
  }
Example #5
0
  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);
  }