@Test
  public void testGetSearchClauseTwoProjects() throws Exception {
    final CustomFieldParamsImpl customFieldParams = new CustomFieldParamsImpl();
    customFieldParams.addValue(Collections.singleton("123"));
    final Map<String, Object> map =
        MapBuilder.<String, Object>newBuilder()
            .add(urlParameterName, customFieldParams)
            .add(
                SystemSearchConstants.forProject().getUrlParameter(),
                CollectionBuilder.list("1", "2"))
            .toMap();
    FieldValuesHolder values = new FieldValuesHolderImpl(map);
    final AtomicBoolean defaultCalled = new AtomicBoolean(false);
    final DefaultIndexedInputHelper helper =
        new DefaultIndexedInputHelper<Version>(
            indexInfoResolver,
            operandResolver,
            fieldFlagOperandRegistry,
            searchContextVisibilityChecker) {
          @Override
          public Clause getClauseForNavigatorValues(final String clauseName, final Set values) {
            return null;
          }
        };

    transformer =
        new VersionCustomFieldSearchInputTransformer(
            urlParameterName,
            clauseNames,
            customField,
            indexInfoResolver,
            operandResolver,
            fieldFlagOperandRegistry,
            searchContextVisibilityChecker,
            versionResolver,
            customFieldInputHelper,
            versionManager) {
          @Override
          protected DefaultIndexedInputHelper getDefaultIndexedInputHelper() {
            defaultCalled.set(true);
            return helper;
          }

          @Override
          protected IndexedInputHelper getIndexedInputHelper() {
            throw new UnsupportedOperationException(
                "Should not have called through to the special indexed input helper");
          }

          @Override
          protected String getClauseName(final User searcher, final ClauseNames clauseNames) {
            return primaryClauseName;
          }
        };
    replay();

    transformer.getSearchClause(theUser, values);
    assertTrue(defaultCalled.get());
  }
Пример #2
0
 public List<GenericValue> findByField(
     final String entityName,
     final String fieldName,
     final Object fieldValue,
     final String orderBy) {
   return findByAnd(
       entityName, new FieldMap(fieldName, fieldValue), CollectionBuilder.list(orderBy));
 }
Пример #3
0
 static {
   DOC_EXAMPLE = new ProjectRoleBean();
   long id = 10360;
   DOC_EXAMPLE.self = Examples.restURI("project/MKY/role/" + id);
   DOC_EXAMPLE.id = id;
   DOC_EXAMPLE.name = "Developers";
   DOC_EXAMPLE.description = "A project role that represents developers in a project";
   DOC_EXAMPLE.actors = CollectionBuilder.list(RoleActorBean.DOC_EXAMPLE);
 }
/**
 * SQL Interceptor that detects changes to the database that aren't xsrf protected
 *
 * @since v4.1
 */
public class XsrfVulnerabilityDetectionSQLInterceptor implements SQLConnectionInterceptor {
  private static final Logger log =
      Logger.getLogger(XsrfVulnerabilityDetectionSQLInterceptor.class);
  private static final String XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE =
      "XsrfVulnerabilityDetectionSQLInterceptorDone";

  @Override
  public void onConnectionTaken(Connection connection, ConnectionPoolState connectionPoolState) {}

  @Override
  public void onConnectionReplaced(
      Connection connection, ConnectionPoolState connectionPoolState) {}

  public void beforeExecution(
      final String sqlString, final List<String> parameterValues, final Statement statement) {}

  public void afterSuccessfulExecution(
      final String sqlString,
      final List<String> parameterValues,
      final Statement statement,
      final ResultSet resultSet,
      final int rowsUpdated) {
    afterExecutionImpl(sqlString);
  }

  public void onException(
      final String sqlString,
      final List<String> parameterValues,
      final Statement statement,
      final SQLException sqlException) {
    afterExecutionImpl(sqlString);
  }

  private boolean isMutatingSQL(String sql) {
    String sqlString = sql.toUpperCase();
    return sqlString.startsWith("INSERT")
        || sqlString.startsWith("UPDATE")
        || sqlString.startsWith("DELETE");
  }

  private void afterExecutionImpl(final String sqlString) {
    if (JiraSystemProperties.getInstance().isXsrfDiagnostics()) {
      final String requestURL = MDC.get("jira.request.url");
      if (isMutatingSQL(sqlString)) {
        HttpServletRequest request = ActionContext.getRequest();
        if (request != null
            && request.getAttribute(XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE) == null) {
          // setting this into the request will make things a lot faster
          request.setAttribute(XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE, "true");
          CallStack callStack = new CallStack();
          if (callStack.hasMethodsWeAreInterestedIn() && !callStack.isProtectedAction()) {
            log.error("XSRF VULNERABILITY DETECTED");
            log.error("requestURL: " + requestURL);
            log.error("sql: " + sqlString);
            log.error("CallStack:", callStack);
          }
        }
      }
    }
  }

  static final List<String> methodsToIgnore =
      CollectionBuilder.list(
          "com.atlassian.sal.jira.lifecycle.JiraLifecycleManager.onJiraStart",
          "com.atlassian.jira.security.login.LoginStoreImpl.recordLoginAttempt",
          "com.atlassian.jira.user.DefaultUserHistoryManager.addItemToHistory");

  static final List<String> actionWhiteList = new ArrayList<String>();

  static {
    if (JiraSystemProperties.isXsrfDetectionCheckRequired()) {
      log.setLevel(Level.INFO);
    }

    LineIterator iterator =
        IOUtils.lineIterator(
            new InputStreamReader(
                XsrfVulnerabilityDetectionSQLInterceptor.class.getResourceAsStream(
                    "/security/xsrf/xsrf-white-list.txt")));
    for (; iterator.hasNext(); ) {
      String line = ((String) iterator.next()).trim();
      if (line.length() > 0 && !line.startsWith("#")) {
        actionWhiteList.add(line);
      }
    }
  }

  private static class CallStack extends RuntimeException {
    public boolean hasMethodsWeAreInterestedIn() {

      for (StackTraceElement element : getStackTrace()) {
        String method = element.getClassName() + "." + element.getMethodName();
        if (methodsToIgnore.contains(method)) {
          return false;
        }
      }

      return true;
    }

    public boolean isProtectedAction() {
      boolean isAnnotated = false;

      StackTraceElement elements[] = getStackTrace();
      for (int i = 0; i < elements.length; i++) {
        StackTraceElement element = elements[i];
        if (isActionSupport_execute(element)) {

          StackTraceElement action = findActionStackTraceElement(elements, i);
          // in OSGI land its possible that we cant see the method in play so
          // if we cant access it then we cant check it
          if (action != null) {

            final String className = action.getClassName();

            try {
              final Class<?> aClass = Class.forName(action.getClassName());
              final Method method = getMethod(aClass, action.getMethodName());
              // in OGSI land its possible that we cant see the method in play so
              // if we cant access it then we cant check it
              if (method != null) {
                isAnnotated = method.isAnnotationPresent(RequiresXsrfCheck.class);
                final String actionMethodName = action.getMethodName();
                final String actionName = className + "." + actionMethodName;
                log.info("ACTION: " + actionName + " PROTECTED: " + isAnnotated);

                final boolean isActionInWhiteList = isActionInWhiteList(aClass);
                if (!isAnnotated) {
                  if (isActionInWhiteList) {
                    // its mutated something and its in the white list of good actions.  Something
                    // is rotten in Denmark!
                    throw new RuntimeException("XSRF white list failure");
                  }
                } else {
                  if (!isActionInWhiteList) {
                    // its a XSRF annotated method but its not in the white list.  We have missed
                    // putting it in the white list
                    throw new RuntimeException(
                        "ACTION: "
                            + actionName
                            + " has XSRF annotated but its not in the whitelist");
                  }
                }
              }
            } catch (ClassNotFoundException e) {
              // ignored
            }
            break; // out of the loop
          }
        }
      }
      return isAnnotated;
    }

    private StackTraceElement findActionStackTraceElement(
        final StackTraceElement[] elements, final int i) {
      StackTraceElement foundElement = null;
      // if the next method is ActionSupport.invokeCommand we need to search up the stack trace
      // until we find a doXXXX method
      StackTraceElement element = elements[i - 1];
      if (isActionSupport_invokeCommand(element)) {
        for (int j = i; j >= 0; j--) {
          element = elements[j];
          if (isActionDoMethod(element)) {
            foundElement = element;
            break;
          }
        }
      }
      return foundElement;
    }

    private boolean isActionSupport_invokeCommand(final StackTraceElement element) {
      return ActionSupport.class.getName().equals(element.getClassName())
          && "invokeCommand".equals(element.getMethodName());
    }

    private boolean isActionSupport_execute(final StackTraceElement element) {
      return ActionSupport.class.getName().equals(element.getClassName())
          && "execute".equals(element.getMethodName());
    }

    private boolean isActionDoMethod(final StackTraceElement element) {
      boolean isok = ActionSupport.class.isAssignableFrom(getClassOfElement(element));
      isok = isok && element.getMethodName().startsWith("do");
      return isok;
    }

    private Class getClassOfElement(final StackTraceElement element) {
      try {
        return Class.forName(element.getClassName());
      } catch (ClassNotFoundException e) {
        return e.getClass();
      }
    }

    private boolean isActionInWhiteList(final Class<?> aClass) {
      // complex name first
      boolean isActionInWhiteList = actionWhiteList.contains(aClass.getName());
      if (!isActionInWhiteList) {
        // simple name last
        isActionInWhiteList = actionWhiteList.contains(aClass.getSimpleName());
      }
      return isActionInWhiteList;
    }

    /**
     * Finds the declared method on the provided class. If the method is not declared on the class,
     * we search recursively up the inheritance hierarchy, stopping at {@link
     * com.atlassian.jira.web.action.JiraWebActionSupport} or {@link Object}.
     *
     * @param clazz the class
     * @param methodName the method name to find
     * @return the method on the class; null if it could not be found.
     */
    private Method getMethod(final Class<?> clazz, final String methodName) {
      try {
        return clazz.getDeclaredMethod(methodName);
      } catch (NoSuchMethodException e) {
        if (clazz.equals(JiraWebActionSupport.class) || clazz.equals(Object.class)) {
          return null;
        } else {
          return getMethod(clazz.getSuperclass(), methodName);
        }
      }
    }
  }
}
  @Test
  public void testExecuteBuildNumberMissing() throws Exception {
    expect(mockBarrier.await(20, TimeUnit.SECONDS)).andReturn(true);
    expect(mockBeanFactory.getInstance(currentUser)).andReturn(new MockI18nHelper()).anyTimes();

    // called during validation!
    expect(mockPermissionManager.hasPermission(Permissions.SYSTEM_ADMIN, currentUser))
        .andReturn(true);

    // This is called during the first parse of the XML file.  At this stage nothing should have
    // been created yet!
    final MockGenericValue mockGv = new MockGenericValue("someentity");
    expect(mockOfBizDelegator.makeValue(EasyMock.<String>anyObject())).andReturn(mockGv).anyTimes();
    expect(mockAttachmentPathManager.getDefaultAttachmentPath())
        .andReturn(directories.get(0).getAbsolutePath())
        .anyTimes();
    expect(mockIndexPathManager.getDefaultIndexRootPath())
        .andReturn(directories.get(1).getAbsolutePath())
        .anyTimes();
    expect(
            mockLicenseStringFactory.create(
                EasyMock.<String>anyObject(), EasyMock.<String>anyObject()))
        .andStubReturn("");

    // after the first parse check the build number.
    expect(mockBuildUtilsInfo.getCurrentBuildNumber()).andStubReturn("1");
    expect(mockBuildUtilsInfo.getMinimumUpgradableBuildNumber()).andStubReturn("0");

    // after the first parse we also verify the license is good.
    expect(
            mockJiraLicenseService.validate(
                EasyMock.<I18nHelper>anyObject(), EasyMock.<String>anyObject()))
        .andStubReturn(mockValidationResult);
    expect(mockValidationResult.getLicenseVersion()).andStubReturn(2);
    expect(mockValidationResult.getErrorCollection()).andStubReturn(new SimpleErrorCollection());

    // this gets called during shutdownAndFlushAsyncServices.  After parse and before the import.
    // This shuts down
    // the scheduler
    expect(mockScheduler.isShutdown()).andReturn(false);
    mockScheduler.shutdown();
    mockMailQueue.sendBuffer();
    expect(mockTaskManager.shutdownAndWait(5)).andReturn(true);

    // Expect AO to be cleared.
    backup.clear();

    // Once the import is running one of the first things to do is to clear out the old database
    // values.
    expect(mockOfBizDelegator.getModelReader()).andReturn(mockModelReader);
    expect(mockModelReader.getEntityNames())
        .andReturn(CollectionBuilder.<String>list("Issue", "User"));
    expect(mockModelReader.getModelEntity("Issue")).andReturn(new ModelEntity());
    expect(mockOfBizDelegator.removeByAnd("Issue", Collections.<String, Object>emptyMap()))
        .andReturn(10);
    expect(mockModelReader.getModelEntity("User")).andReturn(new ModelEntity());
    expect(mockOfBizDelegator.removeByAnd("User", Collections.<String, Object>emptyMap()))
        .andReturn(5);

    // then we go through and create all our GVs (already mocked out during the first parse above)

    // once everything's been imported need to refresh the ofbiz sequencer and check for data
    // consistency.
    mockOfBizDelegator.refreshSequencer();
    mockConsistencyChecker.checkDataConsistency();

    // after the consistency check lets do the upgrade
    expect(mockUpgradeManager.doUpgradeIfNeededAndAllowed(null))
        .andReturn(Collections.<String>emptyList());

    // now do a reindex
    mockIndexManager.deactivate();
    expect(mockIndexManager.size()).andReturn(5);
    expect(mockIndexManager.activate((Context) notNull())).andReturn(1L);

    // raise the JiraStartedEvent
    mockPluginEventManager.broadcast(EasyMock.<JiraStartedEvent>anyObject());

    // finally we can restart the scheduler!
    expect(
            mockScheduler.scheduleJob(
                EasyMock.<JobDetail>anyObject(), EasyMock.<Trigger>anyObject()))
        .andReturn(new Date())
        .anyTimes();
    mockScheduler.start();

    final String filePath = getDataFilePath("jira-export-test-no-build-number.xml");
    final DataImportParams params = new DataImportParams.Builder(filePath).build();

    // Finally everything's mocked out.  Run the import!
    executeTest(params, true, DataImportService.ImportError.NONE);

    // create() should have been called on our GVs
    assertTrue(mockGv.isCreated());
    // the world should have been rebuilt!
    assertTrue(((MockDataImportDependencies) mockDependencies).globalRefreshCalled);
  }
Пример #6
0
  static {
    try {
      IssueBean issue =
          new IssueBean("EX-1", new URI("http://example.com:8080/jira/rest/api/2.0/issue/EX-1"));
      issue.fields =
          new HashMap<String, FieldBean>() {
            {
              put(UPDATED, FieldBean.create(UPDATED, JiraDataTypes.getType(UPDATED), new Date(1)));
              put(
                  DESCRIPTION,
                  FieldBean.create(
                      DESCRIPTION, JiraDataTypes.getType(DESCRIPTION), "example bug report"));
              put(
                  PROJECT,
                  FieldBean.create(
                      PROJECT, JiraDataTypes.getType(PROJECT), ProjectBean.SHORT_DOC_EXAMPLE_1));
              put(
                  TIMETRACKING,
                  FieldBean.create(
                      TIMETRACKING,
                      JiraDataTypes.getType(TIMETRACKING),
                      new TimeTrackingBean(600L, 200L, 400L)));
            }
          };

      issue.addField(
          IssueFieldConstants.ATTACHMENT,
          FieldBean.create(
              IssueFieldConstants.ATTACHMENT,
              JiraDataTypes.getType(IssueFieldConstants.ATTACHMENT),
              CollectionBuilder.list(AttachmentBean.DOC_EXAMPLE)));
      issue.addField(
          IssueFieldConstants.COMMENT,
          FieldBean.create(
              IssueFieldConstants.COMMENT,
              JiraDataTypes.getType(IssueFieldConstants.COMMENT),
              CollectionBuilder.list(CommentBean.DOC_EXAMPLE)));
      issue.addField(
          IssueFieldConstants.WORKLOG,
          FieldBean.create(
              IssueFieldConstants.WORKLOG,
              JiraDataTypes.getType(IssueFieldConstants.WORKLOG),
              CollectionBuilder.list(WorklogBean.DOC_EXAMPLE)));

      issue.addField(
          "sub-tasks",
          FieldBean.create(
              "sub-tasks",
              JiraDataTypes.getType(IssueFieldConstants.ISSUE_LINKS),
              CollectionBuilder.list(
                  new IssueLinkBean(
                      "EX-2",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/EX-2"),
                      LinkedIssueTypeBean.instance()
                          .name("Sub-task")
                          .direction(LinkedIssueTypeBean.Direction.OUTBOUND)
                          .build()))));
      issue.addField(
          "links",
          FieldBean.create(
              "links",
              JiraDataTypes.getType(IssueFieldConstants.ISSUE_LINKS),
              CollectionBuilder.list(
                  new IssueLinkBean(
                      "PRJ-2",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/PRJ-2"),
                      LinkedIssueTypeBean.instance()
                          .name("Dependent")
                          .description("depends on")
                          .direction(LinkedIssueTypeBean.Direction.OUTBOUND)
                          .build()),
                  new IssueLinkBean(
                      "PRJ-3",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/PRJ-3"),
                      LinkedIssueTypeBean.instance()
                          .name("Dependent")
                          .description("is depended by")
                          .direction(LinkedIssueTypeBean.Direction.INBOUND)
                          .build()))));

      issue.addField(
          IssueFieldConstants.WATCHERS,
          FieldBean.create(
              IssueFieldConstants.WATCHERS,
              JiraDataTypes.getType(IssueFieldConstants.WATCHERS),
              WatchersBean.DOC_EXAMPLE));
      // set this as the documentation example
      DOC_EXAMPLE = issue;
    } catch (URISyntaxException e) {
      throw new RuntimeException(e); // never happens
    }
  }