Search in sources :

Example 1 with DecisionRequiredException

use of org.apache.wiki.workflow.DecisionRequiredException in project jspwiki by apache.

the class UserManagerTest method testSetUserProfileWithDenial.

@Test
public void testSetUserProfileWithDenial() throws Exception {
    setUpWithWorkflow();
    // First, count the number of users in the db now.
    int oldUserCount = m_db.getWikiNames().length;
    // Create a new user with random name
    WikiSession session = m_engine.guestSession();
    String loginName = "TestUser" + String.valueOf(System.currentTimeMillis());
    UserProfile profile = m_db.newProfile();
    profile.setEmail("jspwiki.tests@mailinator.com");
    profile.setLoginName(loginName);
    profile.setFullname("FullName" + loginName);
    profile.setPassword("password");
    // Because user profile saves require approvals, we will catch a Redirect
    try {
        m_mgr.setUserProfile(session, profile);
        Assert.fail("We should have caught a DecisionRequiredException caused by approval!");
    } catch (DecisionRequiredException e) {
    }
    // The user should NOT be saved yet
    Assert.assertEquals(oldUserCount, m_db.getWikiNames().length);
    // Now, look in Admin's queue, and verify there's a pending Decision there
    DecisionQueue dq = m_engine.getWorkflowManager().getDecisionQueue();
    Collection decisions = dq.getActorDecisions(m_engine.adminSession());
    Assert.assertEquals(1, decisions.size());
    // Verify that the Decision has all the facts and attributes we need
    Decision d = (Decision) decisions.iterator().next();
    List facts = d.getFacts();
    Assert.assertEquals(new Fact(UserManager.PREFS_FULL_NAME, profile.getFullname()), facts.get(0));
    Assert.assertEquals(new Fact(UserManager.PREFS_LOGIN_NAME, profile.getLoginName()), facts.get(1));
    Assert.assertEquals(new Fact(UserManager.FACT_SUBMITTER, session.getUserPrincipal().getName()), facts.get(2));
    Assert.assertEquals(new Fact(UserManager.PREFS_EMAIL, profile.getEmail()), facts.get(3));
    Assert.assertEquals(profile, d.getWorkflow().getAttribute(UserManager.SAVED_PROFILE));
    // Approve the profile
    d.decide(Outcome.DECISION_DENY);
    // Make sure the profile did NOT save
    Assert.assertEquals(oldUserCount, m_db.getWikiNames().length);
}
Also used : WikiSession(org.apache.wiki.WikiSession) UserProfile(org.apache.wiki.auth.user.UserProfile) DecisionRequiredException(org.apache.wiki.workflow.DecisionRequiredException) DecisionQueue(org.apache.wiki.workflow.DecisionQueue) Collection(java.util.Collection) List(java.util.List) Fact(org.apache.wiki.workflow.Fact) Decision(org.apache.wiki.workflow.Decision) WikiSessionTest(org.apache.wiki.WikiSessionTest) Test(org.junit.Test)

Example 2 with DecisionRequiredException

use of org.apache.wiki.workflow.DecisionRequiredException in project jspwiki by apache.

the class UserManagerTest method testSetUserProfileWithApproval.

@Test
public void testSetUserProfileWithApproval() throws Exception {
    setUpWithWorkflow();
    // First, count the number of users in the db now.
    int oldUserCount = m_db.getWikiNames().length;
    // Create a new user with random name
    WikiSession session = m_engine.guestSession();
    String loginName = "TestUser" + String.valueOf(System.currentTimeMillis());
    UserProfile profile = m_db.newProfile();
    profile.setEmail("jspwiki.tests@mailinator.com");
    profile.setLoginName(loginName);
    profile.setFullname("FullName" + loginName);
    profile.setPassword("password");
    // Because user profile saves require approvals, we will catch a Redirect
    try {
        m_mgr.setUserProfile(session, profile);
        Assert.fail("We should have caught a DecisionRequiredException caused by approval!");
    } catch (DecisionRequiredException e) {
    }
    // The user should NOT be saved yet
    Assert.assertEquals(oldUserCount, m_db.getWikiNames().length);
    // Now, look in Admin's queue, and verify there's a pending Decision there
    DecisionQueue dq = m_engine.getWorkflowManager().getDecisionQueue();
    Collection decisions = dq.getActorDecisions(m_engine.adminSession());
    Assert.assertEquals(1, decisions.size());
    // Verify that the Decision has all the facts and attributes we need
    Decision d = (Decision) decisions.iterator().next();
    List facts = d.getFacts();
    Assert.assertEquals(new Fact(UserManager.PREFS_FULL_NAME, profile.getFullname()), facts.get(0));
    Assert.assertEquals(new Fact(UserManager.PREFS_LOGIN_NAME, profile.getLoginName()), facts.get(1));
    Assert.assertEquals(new Fact(UserManager.FACT_SUBMITTER, session.getUserPrincipal().getName()), facts.get(2));
    Assert.assertEquals(new Fact(UserManager.PREFS_EMAIL, profile.getEmail()), facts.get(3));
    Assert.assertEquals(profile, d.getWorkflow().getAttribute(UserManager.SAVED_PROFILE));
    // Approve the profile
    d.decide(Outcome.DECISION_APPROVE);
    // Make sure the profile saved successfully
    Assert.assertEquals(oldUserCount + 1, m_db.getWikiNames().length);
    // Now delete the profile; should be back to old count
    m_db.deleteByLoginName(loginName);
    Assert.assertEquals(oldUserCount, m_db.getWikiNames().length);
}
Also used : WikiSession(org.apache.wiki.WikiSession) UserProfile(org.apache.wiki.auth.user.UserProfile) DecisionRequiredException(org.apache.wiki.workflow.DecisionRequiredException) DecisionQueue(org.apache.wiki.workflow.DecisionQueue) Collection(java.util.Collection) List(java.util.List) Fact(org.apache.wiki.workflow.Fact) Decision(org.apache.wiki.workflow.Decision) WikiSessionTest(org.apache.wiki.WikiSessionTest) Test(org.junit.Test)

Example 3 with DecisionRequiredException

use of org.apache.wiki.workflow.DecisionRequiredException in project jspwiki by apache.

the class UserManager method setUserProfile.

/**
 * <p>
 * Saves the {@link org.apache.wiki.auth.user.UserProfile}for the user in
 * a wiki session. This method verifies that a user profile to be saved
 * doesn't collide with existing profiles; that is, the login name
 * or full name is already used by another profile. If the profile
 * collides, a <code>DuplicateUserException</code> is thrown. After saving
 * the profile, the user database changes are committed, and the user's
 * credential set is refreshed; if custom authentication is used, this means
 * the user will be automatically be logged in.
 * </p>
 * <p>
 * When the user's profile is saved successfully, this method fires a
 * {@link WikiSecurityEvent#PROFILE_SAVE} event with the WikiSession as the
 * source and the UserProfile as target. For existing profiles, if the
 * user's full name changes, this method also fires a "name changed"
 * event ({@link WikiSecurityEvent#PROFILE_NAME_CHANGED}) with the
 * WikiSession as the source and an array containing the old and new
 * UserProfiles, respectively. The <code>NAME_CHANGED</code> event allows
 * the GroupManager and PageManager can change group memberships and
 * ACLs if needed.
 * </p>
 * <p>
 * Note that WikiSessions normally attach event listeners to the
 * UserManager, so changes to the profile will automatically cause the
 * correct Principals to be reloaded into the current WikiSession's Subject.
 * </p>
 * @param session the wiki session, which may not be <code>null</code>
 * @param profile the user profile, which may not be <code>null</code>
 * @throws DuplicateUserException if the proposed profile's login name or full name collides with another
 * @throws WikiException if the save fails for some reason. If the current user does not have
 * permission to save the profile, this will be a {@link org.apache.wiki.auth.WikiSecurityException};
 * if if the user profile must be approved before it can be saved, it will be a
 * {@link org.apache.wiki.workflow.DecisionRequiredException}. All other WikiException
 * indicate a condition that is not normal is probably due to mis-configuration
 */
public void setUserProfile(WikiSession session, UserProfile profile) throws DuplicateUserException, WikiException {
    // Verify user is allowed to save profile!
    final Permission p = new WikiPermission(m_engine.getApplicationName(), WikiPermission.EDIT_PROFILE_ACTION);
    if (!m_engine.getAuthorizationManager().checkPermission(session, p)) {
        throw new WikiSecurityException("You are not allowed to save wiki profiles.");
    }
    // Check if profile is new, and see if container allows creation
    final boolean newProfile = profile.isNew();
    // Check if another user profile already has the fullname or loginname
    final UserProfile oldProfile = getUserProfile(session);
    final boolean nameChanged = (oldProfile == null || oldProfile.getFullname() == null) ? false : !(oldProfile.getFullname().equals(profile.getFullname()) && oldProfile.getLoginName().equals(profile.getLoginName()));
    UserProfile otherProfile;
    try {
        otherProfile = getUserDatabase().findByLoginName(profile.getLoginName());
        if (otherProfile != null && !otherProfile.equals(oldProfile)) {
            throw new DuplicateUserException("security.error.login.taken", profile.getLoginName());
        }
    } catch (final NoSuchPrincipalException e) {
    }
    try {
        otherProfile = getUserDatabase().findByFullName(profile.getFullname());
        if (otherProfile != null && !otherProfile.equals(oldProfile)) {
            throw new DuplicateUserException("security.error.fullname.taken", profile.getFullname());
        }
    } catch (final NoSuchPrincipalException e) {
    }
    // For new accounts, create approval workflow for user profile save.
    if (newProfile && oldProfile != null && oldProfile.isNew()) {
        final WorkflowBuilder builder = WorkflowBuilder.getBuilder(m_engine);
        final Principal submitter = session.getUserPrincipal();
        final Task completionTask = new SaveUserProfileTask(m_engine, session.getLocale());
        // Add user profile attribute as Facts for the approver (if required)
        final boolean hasEmail = profile.getEmail() != null;
        final Fact[] facts = new Fact[hasEmail ? 4 : 3];
        facts[0] = new Fact(PREFS_FULL_NAME, profile.getFullname());
        facts[1] = new Fact(PREFS_LOGIN_NAME, profile.getLoginName());
        facts[2] = new Fact(FACT_SUBMITTER, submitter.getName());
        if (hasEmail) {
            facts[3] = new Fact(PREFS_EMAIL, profile.getEmail());
        }
        final Workflow workflow = builder.buildApprovalWorkflow(submitter, SAVE_APPROVER, null, SAVE_DECISION_MESSAGE_KEY, facts, completionTask, null);
        workflow.setAttribute(SAVED_PROFILE, profile);
        m_engine.getWorkflowManager().start(workflow);
        final boolean approvalRequired = workflow.getCurrentStep() instanceof Decision;
        // If the profile requires approval, redirect user to message page
        if (approvalRequired) {
            throw new DecisionRequiredException("This profile must be approved before it becomes active");
        }
        try {
            final AuthenticationManager mgr = m_engine.getAuthenticationManager();
            if (newProfile && !mgr.isContainerAuthenticated()) {
                mgr.login(session, null, profile.getLoginName(), profile.getPassword());
            }
        } catch (final WikiException e) {
            throw new WikiSecurityException(e.getMessage(), e);
        }
        // Alert all listeners that the profile changed...
        // ...this will cause credentials to be reloaded in the wiki session
        fireEvent(WikiSecurityEvent.PROFILE_SAVE, session, profile);
    } else // For existing accounts, just save the profile
    {
        // If login name changed, rename it first
        if (nameChanged && oldProfile != null && !oldProfile.getLoginName().equals(profile.getLoginName())) {
            getUserDatabase().rename(oldProfile.getLoginName(), profile.getLoginName());
        }
        // Now, save the profile (userdatabase will take care of timestamps for us)
        getUserDatabase().save(profile);
        if (nameChanged) {
            // Fire an event if the login name or full name changed
            final UserProfile[] profiles = new UserProfile[] { oldProfile, profile };
            fireEvent(WikiSecurityEvent.PROFILE_NAME_CHANGED, session, profiles);
        } else {
            // Fire an event that says we have new a new profile (new principals)
            fireEvent(WikiSecurityEvent.PROFILE_SAVE, session, profile);
        }
    }
}
Also used : Task(org.apache.wiki.workflow.Task) WikiException(org.apache.wiki.api.exceptions.WikiException) UserProfile(org.apache.wiki.auth.user.UserProfile) DecisionRequiredException(org.apache.wiki.workflow.DecisionRequiredException) Workflow(org.apache.wiki.workflow.Workflow) DuplicateUserException(org.apache.wiki.auth.user.DuplicateUserException) Fact(org.apache.wiki.workflow.Fact) Decision(org.apache.wiki.workflow.Decision) WikiPermission(org.apache.wiki.auth.permissions.WikiPermission) Permission(java.security.Permission) AllPermission(org.apache.wiki.auth.permissions.AllPermission) WorkflowBuilder(org.apache.wiki.workflow.WorkflowBuilder) WikiPermission(org.apache.wiki.auth.permissions.WikiPermission) Principal(java.security.Principal)

Example 4 with DecisionRequiredException

use of org.apache.wiki.workflow.DecisionRequiredException in project jspwiki by apache.

the class WikiEngine method saveText.

/**
 *  Writes the WikiText of a page into the
 *  page repository. If the <code>jspwiki.properties</code> file contains
 *  the property <code>jspwiki.approver.workflow.saveWikiPage</code> and
 *  its value resolves to a valid user, {@link org.apache.wiki.auth.authorize.Group}
 *  or {@link org.apache.wiki.auth.authorize.Role}, this method will
 *  place a {@link org.apache.wiki.workflow.Decision} in the approver's
 *  workflow inbox and throw a {@link org.apache.wiki.workflow.DecisionRequiredException}.
 *  If the submitting user is authenticated and the page save is rejected,
 *  a notification will be placed in the user's decision queue.
 *
 *  @since 2.1.28
 *  @param context The current WikiContext
 *  @param text    The Wiki markup for the page.
 *  @throws WikiException if the save operation encounters an error during the
 *  save operation. If the page-save operation requires approval, the exception will
 *  be of type {@link org.apache.wiki.workflow.DecisionRequiredException}. Individual
 *  PageFilters, such as the {@link org.apache.wiki.filters.SpamFilter} may also
 *  throw a {@link org.apache.wiki.api.exceptions.RedirectException}.
 */
public void saveText(WikiContext context, String text) throws WikiException {
    // Check if page data actually changed; bail if not
    WikiPage page = context.getPage();
    String oldText = getPureText(page);
    String proposedText = TextUtil.normalizePostData(text);
    if (oldText != null && oldText.equals(proposedText)) {
        return;
    }
    // Check if creation of empty pages is allowed; bail if not
    boolean allowEmpty = TextUtil.getBooleanProperty(m_properties, PROP_ALLOW_CREATION_OF_EMPTY_PAGES, false);
    if (!allowEmpty && !pageExists(page) && text.trim().equals("")) {
        return;
    }
    // Create approval workflow for page save; add the diffed, proposed
    // and old text versions as Facts for the approver (if approval is required)
    // If submitter is authenticated, any reject messages will appear in his/her workflow inbox.
    WorkflowBuilder builder = WorkflowBuilder.getBuilder(this);
    Principal submitter = context.getCurrentUser();
    Task prepTask = new PageManager.PreSaveWikiPageTask(context, proposedText);
    Task completionTask = new PageManager.SaveWikiPageTask();
    String diffText = m_differenceManager.makeDiff(context, oldText, proposedText);
    boolean isAuthenticated = context.getWikiSession().isAuthenticated();
    Fact[] facts = new Fact[5];
    facts[0] = new Fact(PageManager.FACT_PAGE_NAME, page.getName());
    facts[1] = new Fact(PageManager.FACT_DIFF_TEXT, diffText);
    facts[2] = new Fact(PageManager.FACT_PROPOSED_TEXT, proposedText);
    facts[3] = new Fact(PageManager.FACT_CURRENT_TEXT, oldText);
    facts[4] = new Fact(PageManager.FACT_IS_AUTHENTICATED, Boolean.valueOf(isAuthenticated));
    String rejectKey = isAuthenticated ? PageManager.SAVE_REJECT_MESSAGE_KEY : null;
    Workflow workflow = builder.buildApprovalWorkflow(submitter, PageManager.SAVE_APPROVER, prepTask, PageManager.SAVE_DECISION_MESSAGE_KEY, facts, completionTask, rejectKey);
    m_workflowMgr.start(workflow);
    // Let callers know if the page-save requires approval
    if (workflow.getCurrentStep() instanceof Decision) {
        throw new DecisionRequiredException("The page contents must be approved before they become active.");
    }
}
Also used : Task(org.apache.wiki.workflow.Task) DecisionRequiredException(org.apache.wiki.workflow.DecisionRequiredException) Workflow(org.apache.wiki.workflow.Workflow) Fact(org.apache.wiki.workflow.Fact) Decision(org.apache.wiki.workflow.Decision) WorkflowBuilder(org.apache.wiki.workflow.WorkflowBuilder) Principal(java.security.Principal)

Aggregations

Decision (org.apache.wiki.workflow.Decision)4 DecisionRequiredException (org.apache.wiki.workflow.DecisionRequiredException)4 Fact (org.apache.wiki.workflow.Fact)4 UserProfile (org.apache.wiki.auth.user.UserProfile)3 Principal (java.security.Principal)2 Collection (java.util.Collection)2 List (java.util.List)2 WikiSession (org.apache.wiki.WikiSession)2 WikiSessionTest (org.apache.wiki.WikiSessionTest)2 DecisionQueue (org.apache.wiki.workflow.DecisionQueue)2 Task (org.apache.wiki.workflow.Task)2 Workflow (org.apache.wiki.workflow.Workflow)2 WorkflowBuilder (org.apache.wiki.workflow.WorkflowBuilder)2 Test (org.junit.Test)2 Permission (java.security.Permission)1 WikiException (org.apache.wiki.api.exceptions.WikiException)1 AllPermission (org.apache.wiki.auth.permissions.AllPermission)1 WikiPermission (org.apache.wiki.auth.permissions.WikiPermission)1 DuplicateUserException (org.apache.wiki.auth.user.DuplicateUserException)1