/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Structr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.web.advanced; import com.jayway.restassured.RestAssured; import com.jayway.restassured.filter.session.SessionFilter; import org.hamcrest.Matchers; import static org.hamcrest.Matchers.equalTo; import org.junit.Assert; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import org.junit.Test; import org.structr.api.config.Settings; import org.structr.common.error.FrameworkException; import org.structr.core.graph.NodeAttribute; import org.structr.core.graph.Tx; import org.structr.web.StructrUiTest; import org.structr.web.auth.UiAuthenticator; import org.structr.web.entity.User; import org.structr.web.entity.dom.DOMNode; import org.structr.web.entity.dom.Page; import org.structr.web.servlet.HtmlServlet; /** * * @author Christian Morgner */ public class UserSelfRegistrationTest extends StructrUiTest { @Test public void testUserSelfRegistration() { // since we cannot test the mail confirmation workflow, we just disable sending an e-mail Settings.SmtpTesting.setValue(true); // enable self-registration and auto-login Settings.RestUserAutocreate.setValue(true); Settings.RestUserAutologin.setValue(true); final String eMail = "test@structr.com"; String id = null; String confKey = null; // switch to REST servlet RestAssured.basePath = restUrl; grant("_registration", UiAuthenticator.NON_AUTH_USER_POST, true); grant("_login", UiAuthenticator.NON_AUTH_USER_POST, false); // verify self registration RestAssured .given() .body("{ name: '" + eMail + "', eMail: '" + eMail + "' }") .expect() .statusCode(201) .when() .post("/registration"); try (final Tx tx = app.tx()) { final User user = app.nodeQuery(User.class).getFirst(); assertNotNull("User was not created", user); // store ID for later user id = user.getProperty(User.id); confKey = user.getProperty(User.confirmationKey); assertNotNull("Confirmation key was not set", confKey); tx.success(); } catch (FrameworkException t) { fail("Unexpected exception."); } // switch to HTML servlet RestAssured.basePath = htmlUrl; // access the user confirmation page RestAssured .given() .param(HtmlServlet.CONFIRM_KEY_KEY, confKey) .expect() .statusCode(200) .when() .get(HtmlServlet.CONFIRM_REGISTRATION_PAGE); // verify that the user has no confirmation key try (final Tx tx = app.tx()) { final User user = app.nodeQuery(User.class).getFirst(); assertNotNull("User was not created", user); // store ID for later user id = user.getProperty(User.id); confKey = user.getProperty(User.confirmationKey); assertNull("Confirmation key was set after confirmation", confKey); tx.success(); } catch (FrameworkException t) { fail("Unexpected exception."); } } @Test public void testUserSelfRegistrationWithRedirect() { // since we cannot test the mail confirmation workflow, we just disable sending an e-mail Settings.SmtpTesting.setValue(true); // enable self-registration and auto-login Settings.RestUserAutocreate.setValue(true); Settings.RestUserAutologin.setValue(true); final SessionFilter sessionFilter = new SessionFilter(); final String eMail = "test@structr.com"; String id = null; String confKey = null; // switch to REST servlet RestAssured.basePath = restUrl; grant("_registration", UiAuthenticator.NON_AUTH_USER_POST, true); grant("_login", UiAuthenticator.NON_AUTH_USER_POST, false); // verify self registration RestAssured .given() .filter(sessionFilter) .body("{ name: '" + eMail + "', eMail: '" + eMail + "' }") .expect() .statusCode(201) .when() .post("/registration"); try (final Tx tx = app.tx()) { final User user = app.nodeQuery(User.class).getFirst(); assertNotNull("User was not created", user); // store ID for later user id = user.getProperty(User.id); confKey = user.getProperty(User.confirmationKey); assertNotNull("Confirmation key was not set", confKey); tx.success(); } catch (FrameworkException t) { fail("Unexpected exception."); } // create redirect page try (final Tx tx = app.tx()) { makeVisible(Page.createSimplePage(securityContext, "error"), true); makeVisible(Page.createSimplePage(securityContext, "success"), false); tx.success(); } catch (FrameworkException fex) {} // switch to HTML servlet RestAssured.basePath = htmlUrl; // expect 404 Not Found when logging in because Jetty or // RestAssured don't preserve the session ID RestAssured .given() .filter(sessionFilter) .param(HtmlServlet.CONFIRM_KEY_KEY, confKey) .param(HtmlServlet.TARGET_PAGE_KEY, "success") .expect() .statusCode(200) .body("html.head.title", Matchers.equalTo("Success")) .body("html.body.h1", Matchers.equalTo("Success")) .body("html.body.div", Matchers.equalTo("Initial body text")) .when() .get(HtmlServlet.CONFIRM_REGISTRATION_PAGE); // verify that the user has no confirmation key try (final Tx tx = app.tx()) { final User user = app.nodeQuery(User.class).getFirst(); assertNotNull("User was not created", user); assertNull("Confirmation key was set after confirmation", user.getProperty(User.confirmationKey)); final String[] sessionIds = user.getProperty(User.sessionIds); Assert.assertEquals("Invalid number of sessions after user confirmation", 1, sessionIds.length); Assert.assertEquals("Invalid session ID after user confirmation", sessionFilter.getSessionId(), sessionIds[0]); tx.success(); } catch (FrameworkException t) { fail("Unexpected exception."); } } @Test public void testResetPassword() { final String eMail = "test@structr.com"; String id = null; // since we cannot test the mail confirmation workflow, we just disable sending an e-mail Settings.SmtpTesting.setValue(true); // switch to REST servlet RestAssured.basePath = restUrl; grant("_resetPassword", UiAuthenticator.NON_AUTH_USER_POST, true); grant("_login", UiAuthenticator.NON_AUTH_USER_POST, false); try (final Tx tx = app.tx()) { final User user = app.create(User.class, new NodeAttribute<>(User.name, "tester"), new NodeAttribute<>(User.eMail, eMail), new NodeAttribute<>(User.password, "correct") ); // store ID for later user id = user.getProperty(User.id); tx.success(); } catch (Throwable t) { fail("Unexpected exception."); } // verify failing login RestAssured .given() .body("{ eMail: '" + eMail + "', password: 'incorrect' }") .expect() .statusCode(401) .body("code", equalTo(401)) .body("message", equalTo("Wrong username or password, or user is blocked. Check caps lock. Note: Username is case sensitive!")) .when() .post("/login"); // verify successful login RestAssured .given() .body("{ eMail: '" + eMail + "', password: 'correct' }") .expect() .statusCode(200) .body("result.type", equalTo("User")) .body("result.name", equalTo("tester")) .body("result.isUser", equalTo(true)) .body("result.id", equalTo(id)) .when() .post("/login"); // verify reset password doesn't disclose information about existing users RestAssured .given() .body("{ eMail: 'unknown@structr.com' }") .expect() .statusCode(200) .when() .post("/reset-password"); RestAssured .given() .body("{ eMail: '" + eMail + "' }") .expect() .statusCode(200) .when() .post("/reset-password"); } // ----- private methods ----- private <T extends DOMNode> T makeVisible(final T src, final boolean publicToo) { try { src.setProperty(DOMNode.visibleToAuthenticatedUsers, true); if (publicToo) { src.setProperty(DOMNode.visibleToPublicUsers, true); } } catch (FrameworkException fex) {} src.getAllChildNodes().stream().forEach((n) -> { try { n.setProperty(DOMNode.visibleToAuthenticatedUsers, true); if (publicToo) { src.setProperty(DOMNode.visibleToPublicUsers, true); } } catch (FrameworkException fex) {} } ); return src; } }