blob: c45ea196cdba6871795b09e3992e60e0cca01bf8 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.wiki.auth.user;
import java.io.File;
import java.io.Serializable;
import java.security.Principal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameAlreadyBoundException;
import javax.sql.DataSource;
import org.apache.wiki.HsqlDbUtils;
import org.apache.wiki.TestJDBCDataSource;
import org.apache.wiki.TestJNDIContext;
import org.apache.wiki.auth.NoSuchPrincipalException;
import org.apache.wiki.auth.WikiSecurityException;
import org.apache.wiki.util.CryptoUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
*/
public class JDBCUserDatabaseTest
{
private final HsqlDbUtils m_hu = new HsqlDbUtils();
private JDBCUserDatabase m_db = null;
private static final String TEST_ATTRIBUTES = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAACdAAKYXR0cmlidXRlMXQAEXNvbWUgcmFuZG9tIHZhbHVldAAKYXR0cmlidXRlMnQADWFub3RoZXIgdmFsdWV4";
private static final String INSERT_JANNE = "INSERT INTO users (" +
JDBCUserDatabase.DEFAULT_DB_UID + "," +
JDBCUserDatabase.DEFAULT_DB_EMAIL + "," +
JDBCUserDatabase.DEFAULT_DB_FULL_NAME + "," +
JDBCUserDatabase.DEFAULT_DB_LOGIN_NAME + "," +
JDBCUserDatabase.DEFAULT_DB_PASSWORD + "," +
JDBCUserDatabase.DEFAULT_DB_WIKI_NAME + "," +
JDBCUserDatabase.DEFAULT_DB_CREATED + "," +
JDBCUserDatabase.DEFAULT_DB_ATTRIBUTES + ") VALUES (" +
"'-7739839977499061014'," + "'janne@ecyrd.com'," + "'Janne Jalkanen'," + "'janne'," +
"'{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee'," +
"'JanneJalkanen'," +
"'" + new Timestamp( new Timestamp( System.currentTimeMillis() ).getTime() ).toString() + "'," +
"'" + TEST_ATTRIBUTES +"'" + ");";
private static final String INSERT_USER = "INSERT INTO users (" +
JDBCUserDatabase.DEFAULT_DB_UID + "," +
JDBCUserDatabase.DEFAULT_DB_EMAIL + "," +
JDBCUserDatabase.DEFAULT_DB_LOGIN_NAME + "," +
JDBCUserDatabase.DEFAULT_DB_PASSWORD + "," +
JDBCUserDatabase.DEFAULT_DB_CREATED + ") VALUES (" +
"'-8629747547991531672'," + "'jspwiki.tests@mailinator.com'," + "'user'," +
"'{SHA}5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'," +
"'" + new Timestamp( new Timestamp( System.currentTimeMillis() ).getTime() ).toString() + "'" + ");";
/**
*
*/
@BeforeEach
public void setUp() throws Exception
{
m_hu.setUp();
// Set up the mock JNDI initial context
TestJNDIContext.initialize();
final Context initCtx = new InitialContext();
try
{
initCtx.bind( "java:comp/env", new TestJNDIContext() );
}
catch( final NameAlreadyBoundException e )
{
// ignore
}
final Context ctx = (Context) initCtx.lookup( "java:comp/env" );
final DataSource ds = new TestJDBCDataSource( new File( "target/test-classes/jspwiki-custom.properties" ) );
ctx.bind( JDBCUserDatabase.DEFAULT_DB_JNDI_NAME, ds );
// Get the JDBC connection and init tables
try
{
final Connection conn = ds.getConnection();
final Statement stmt = conn.createStatement();
final String sql;
sql = "DELETE FROM " + JDBCUserDatabase.DEFAULT_DB_TABLE + ";";
stmt.executeUpdate( sql );
// Create a new test user 'janne'
stmt.executeUpdate( INSERT_JANNE );
// Create a new test user 'user'
stmt.executeUpdate( INSERT_USER );
stmt.close();
conn.close();
// Initialize the user database
m_db = new JDBCUserDatabase();
m_db.initialize( null, new Properties() );
}
catch( final SQLException e )
{
Assertions.fail("Looks like your database could not be connected to - "+
"please make sure that you have started your database, exception: " + e.getMessage());
}
}
@AfterEach
public void tearDown() throws Exception
{
m_hu.tearDown();
}
@Test
public void testDeleteByLoginName() throws WikiSecurityException
{
// First, count the number of users in the db now.
final int oldUserCount = m_db.getWikiNames().length;
// Create a new user with random name
final 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");
m_db.save(profile);
// Make sure the profile saved successfully
profile = m_db.findByLoginName( loginName );
Assertions.assertEquals( loginName, profile.getLoginName() );
Assertions.assertEquals( oldUserCount+1, m_db.getWikiNames().length );
// Now delete the profile; should be back to old count
m_db.deleteByLoginName( loginName );
Assertions.assertEquals( oldUserCount, m_db.getWikiNames().length );
}
@Test
public void testAttributes() throws Exception
{
UserProfile profile = m_db.findByEmail( "janne@ecyrd.com" );
Map<String,Serializable> attributes = profile.getAttributes();
Assertions.assertEquals( 2, attributes.size() );
Assertions.assertTrue( attributes.containsKey( "attribute1" ) );
Assertions.assertTrue( attributes.containsKey( "attribute2" ) );
Assertions.assertEquals( "some random value", attributes.get( "attribute1" ) );
Assertions.assertEquals( "another value", attributes.get( "attribute2" ) );
// Change attribute 1, and add another one
attributes.put( "attribute1", "replacement value" );
attributes.put( "attribute the third", "some value" );
m_db.save( profile );
// Retrieve the profile again and make sure our values got saved
profile = m_db.findByEmail( "janne@ecyrd.com" );
attributes = profile.getAttributes();
Assertions.assertEquals( 3, attributes.size() );
Assertions.assertTrue( attributes.containsKey( "attribute1" ) );
Assertions.assertTrue( attributes.containsKey( "attribute2" ) );
Assertions.assertTrue( attributes.containsKey( "attribute the third" ) );
Assertions.assertEquals( "replacement value", attributes.get( "attribute1" ) );
Assertions.assertEquals( "another value", attributes.get( "attribute2" ) );
Assertions.assertEquals( "some value", attributes.get( "attribute the third" ) );
// Restore the original attributes and re-save
attributes.put( "attribute1", "some random value" );
attributes.remove( "attribute the third" );
m_db.save( profile );
}
@Test
public void testFindByEmail()
{
try
{
final UserProfile profile = m_db.findByEmail( "janne@ecyrd.com" );
Assertions.assertEquals( "-7739839977499061014", profile.getUid() );
Assertions.assertEquals( "janne", profile.getLoginName() );
Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
Assertions.assertEquals( "{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee", profile.getPassword() );
Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNull( profile.getLastModified() );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
try
{
m_db.findByEmail( "foo@bar.org" );
// We should never get here
Assertions.assertTrue( false );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( true );
}
}
@Test
public void testFindByFullName()
{
try
{
final UserProfile profile = m_db.findByFullName( "Janne Jalkanen" );
Assertions.assertEquals( "-7739839977499061014", profile.getUid() );
Assertions.assertEquals( "janne", profile.getLoginName() );
Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
Assertions.assertEquals( "{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee", profile.getPassword() );
Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNull( profile.getLastModified() );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
try
{
m_db.findByEmail( "foo@bar.org" );
// We should never get here
Assertions.assertTrue( false );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( true );
}
}
@Test
public void testFindByUid()
{
try
{
final UserProfile profile = m_db.findByUid( "-7739839977499061014" );
Assertions.assertEquals( "-7739839977499061014", profile.getUid() );
Assertions.assertEquals( "janne", profile.getLoginName() );
Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
Assertions.assertEquals( "{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee", profile.getPassword() );
Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNull( profile.getLastModified() );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
try
{
m_db.findByEmail( "foo@bar.org" );
// We should never get here
Assertions.assertTrue( false );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( true );
}
}
@Test
public void testFindByWikiName()
{
try
{
final UserProfile profile = m_db.findByWikiName( "JanneJalkanen" );
Assertions.assertEquals( "-7739839977499061014", profile.getUid() );
Assertions.assertEquals( "janne", profile.getLoginName() );
Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
Assertions.assertEquals( "{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee", profile.getPassword() );
Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNull( profile.getLastModified() );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
try
{
m_db.findByEmail( "foo" );
// We should never get here
Assertions.assertTrue( false );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( true );
}
}
@Test
public void testFindByLoginName()
{
try
{
final UserProfile profile = m_db.findByLoginName( "janne" );
Assertions.assertEquals( "-7739839977499061014", profile.getUid() );
Assertions.assertEquals( "janne", profile.getLoginName() );
Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
Assertions.assertEquals( "{SHA}457b08e825da547c3b77fbc1ff906a1d00a7daee", profile.getPassword() );
Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNull( profile.getLastModified() );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
try
{
m_db.findByEmail( "FooBar" );
// We should never get here
Assertions.assertTrue( false );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( true );
}
}
@Test
public void testGetWikiName() throws WikiSecurityException
{
final Principal[] principals = m_db.getWikiNames();
Assertions.assertEquals( 1, principals.length );
}
@Test
public void testRename() throws Exception
{
// Try renaming a non-existent profile; it should Assertions.fail
try
{
m_db.rename( "nonexistentname", "renameduser" );
Assertions.fail( "Should not have allowed rename..." );
}
catch ( final NoSuchPrincipalException e )
{
// Cool; that's what we expect
}
// Create new user & verify it saved ok
UserProfile profile = m_db.newProfile();
profile.setEmail( "renamed@mailinator.com" );
profile.setFullname( "Renamed User" );
profile.setLoginName( "olduser" );
profile.setPassword( "password" );
m_db.save( profile );
profile = m_db.findByLoginName( "olduser" );
Assertions.assertNotNull( profile );
// Try renaming to a login name that's already taken; it should Assertions.fail
try
{
m_db.rename( "olduser", "janne" );
Assertions.fail( "Should not have allowed rename..." );
}
catch ( final DuplicateUserException e )
{
// Cool; that's what we expect
}
// Now, rename it to an unused name
m_db.rename( "olduser", "renameduser" );
// The old user shouldn't be found
try
{
profile = m_db.findByLoginName( "olduser" );
Assertions.fail( "Old user was found, but it shouldn't have been." );
}
catch ( final NoSuchPrincipalException e )
{
// Cool, it's gone
}
// The new profile should be found, and its properties should match the old ones
profile = m_db.findByLoginName( "renameduser" );
Assertions.assertEquals( "renamed@mailinator.com", profile.getEmail() );
Assertions.assertEquals( "Renamed User", profile.getFullname() );
Assertions.assertEquals( "renameduser", profile.getLoginName() );
Assertions.assertTrue( CryptoUtil.verifySaltedPassword( "password".getBytes(), profile.getPassword() ) );
// Delete the user
m_db.deleteByLoginName( "renameduser" );
}
@Test
public void testSave() throws Exception
{
try
{
// Overwrite existing user
UserProfile profile = m_db.newProfile();
profile.setEmail( "jspwiki.tests@mailinator.com" );
profile.setFullname( "Test User" );
profile.setLoginName( "user" );
profile.setPassword( "password" );
m_db.save( profile );
profile = m_db.findByEmail( "jspwiki.tests@mailinator.com" );
Assertions.assertEquals( "jspwiki.tests@mailinator.com", profile.getEmail() );
Assertions.assertEquals( "Test User", profile.getFullname() );
Assertions.assertEquals( "user", profile.getLoginName() );
Assertions.assertTrue( CryptoUtil.verifySaltedPassword( "password".getBytes(), profile.getPassword() ) );
Assertions.assertEquals( "TestUser", profile.getWikiName() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNotNull( profile.getLastModified() );
Assertions.assertNotSame( profile.getCreated(), profile.getLastModified() );
// Create new user
profile = m_db.newProfile();
profile.setEmail( "jspwiki.tests2@mailinator.com" );
profile.setFullname( "Test User 2" );
profile.setLoginName( "user2" );
profile.setPassword( "password" );
m_db.save( profile );
profile = m_db.findByEmail( "jspwiki.tests2@mailinator.com" );
Assertions.assertEquals( "jspwiki.tests2@mailinator.com", profile.getEmail() );
Assertions.assertEquals( "Test User 2", profile.getFullname() );
Assertions.assertEquals( "user2", profile.getLoginName() );
Assertions.assertTrue( CryptoUtil.verifySaltedPassword( "password".getBytes(), profile.getPassword() ) );
Assertions.assertEquals( "TestUser2", profile.getWikiName() );
Assertions.assertNotNull( profile.getCreated() );
Assertions.assertNotNull( profile.getLastModified() );
Assertions.assertEquals( profile.getCreated(), profile.getLastModified() );
// Make sure we can find it by uid
final String uid = profile.getUid();
Assertions.assertNotNull( m_db.findByUid( uid ) );
}
catch( final NoSuchPrincipalException e )
{
Assertions.assertTrue( false );
}
catch( final WikiSecurityException e )
{
Assertions.assertTrue( false );
}
}
@Test
public void testValidatePassword()
{
Assertions.assertFalse( m_db.validatePassword( "janne", "test" ) );
Assertions.assertTrue( m_db.validatePassword( "janne", "myP@5sw0rd" ) );
Assertions.assertTrue( m_db.validatePassword( "user", "password" ) );
}
}