diff --git a/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template b/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template index 1359ada36..b4d55df74 100644 --- a/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template +++ b/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template @@ -19,7 +19,7 @@ @author Apache Directory Project --> - + diff --git a/pom.xml b/pom.xml index 7a8dd4174..1c6e02458 100644 --- a/pom.xml +++ b/pom.xml @@ -94,8 +94,8 @@ 3.12.0 2.9.0 2.9.0 - 2.0.2 - 2.0.2 + 2.0.3-SNAPSHOT + 2.0.3.SNAPSHOT 2.0.0.AM26 2.1.3 2.1.3 diff --git a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/core/DirectoryApiConnectionWrapperTest.java b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/core/DirectoryApiConnectionWrapperTest.java index 1e7cef8a9..2509959f3 100644 --- a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/core/DirectoryApiConnectionWrapperTest.java +++ b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/core/DirectoryApiConnectionWrapperTest.java @@ -92,7 +92,6 @@ import org.apache.directory.studio.connection.core.ConnectionParameter; import org.apache.directory.studio.connection.core.ConnectionParameter.AuthenticationMethod; import org.apache.directory.studio.connection.core.ConnectionParameter.EncryptionMethod; -import org.apache.directory.studio.connection.core.ConnectionParameter.Krb5Configuration; import org.apache.directory.studio.connection.core.ConnectionParameter.Krb5CredentialConfiguration; import org.apache.directory.studio.connection.core.ICertificateHandler.TrustLevel; import org.apache.directory.studio.connection.core.IReferralHandler; @@ -378,16 +377,45 @@ public void testSimpleBindStartTls( TestLdapServer ldapServer ) /** - * Test binding to the server using SASL and no encryption. + * Test binding to the server using SASL auth and no encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All) - public void testSaslBindPlain( TestLdapServer ldapServer ) + public void testSaslDigestMd5BindAuthPlain( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindPlain( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using SASL auth-int and no encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthIntPlain( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindPlain( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using SASL auth-conf and no encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthConfPlain( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindPlain( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslDigestMd5BindPlain( TestLdapServer ldapServer, SaslQoP saslQoP ) { ldapServer.setConfidentialityRequired( false ); StudioProgressMonitor monitor = getProgressMonitor(); Connection connection = getConnection( monitor, ldapServer, "user.1", "password" ); connection.setAuthMethod( AuthenticationMethod.SASL_DIGEST_MD5 ); + connection.getConnectionParameter().setSaslQop( SaslQoP.AUTH_CONF ); assertFalse( connectionWrapper.isConnected() ); @@ -432,11 +460,39 @@ public void testSaslBindPlainConfidentiallyRequired( TestLdapServer ldapServer ) /** - * Test binding to the server using SASL and ldaps:// encryption. + * Test binding to the server using SASL auth and ldaps:// encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthLdaps( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindLdaps( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using SASL auth-int and ldaps:// encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthIntLdaps( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindLdaps( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using SASL auth-conf and ldaps:// encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All) - public void testSaslBindLdaps( TestLdapServer ldapServer ) + public void testSaslDigestMd5BindAuthConfLdaps( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindLdaps( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslDigestMd5BindLdaps( TestLdapServer ldapServer, SaslQoP saslQoP ) { ldapServer.setConfidentialityRequired( true ); StudioProgressMonitor monitor = getProgressMonitor(); @@ -444,6 +500,7 @@ public void testSaslBindLdaps( TestLdapServer ldapServer ) connection.setPort( ldapServer.getPortSSL() ); connection.setEncryptionMethod( EncryptionMethod.LDAPS ); connection.setAuthMethod( AuthenticationMethod.SASL_DIGEST_MD5 ); + connection.getConnectionParameter().setSaslQop( saslQoP ); acceptAllCertificates(); assertFalse( connectionWrapper.isConnected() ); @@ -462,17 +519,46 @@ public void testSaslBindLdaps( TestLdapServer ldapServer ) /** - * Test binding to the server using SASL and StartTLS encryption. + * Test binding to the server using SASL auth and StartTLS encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthStartTls( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindStartTls( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using SASL auth-int and StartTLS encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds) + public void testSaslDigestMd5BindAuthIntStartTls( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindStartTls( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using SASL auth-conf and StartTLS encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All) - public void testSaslBindStartTls( TestLdapServer ldapServer ) + public void testSaslDigestMd5BindAuthConfStartTls( TestLdapServer ldapServer ) + { + testSaslDigestMd5BindStartTls( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslDigestMd5BindStartTls( TestLdapServer ldapServer, SaslQoP saslQoP ) { ldapServer.setConfidentialityRequired( true ); StudioProgressMonitor monitor = getProgressMonitor(); Connection connection = getConnection( monitor, ldapServer, "user.1", "password" ); connection.setEncryptionMethod( EncryptionMethod.START_TLS ); connection.setAuthMethod( AuthenticationMethod.SASL_DIGEST_MD5 ); + connection.getConnectionParameter().setSaslQop( saslQoP ); acceptAllCertificates(); assertFalse( connectionWrapper.isConnected() ); @@ -491,11 +577,39 @@ public void testSaslBindStartTls( TestLdapServer ldapServer ) /** - * Test binding to the server using GSSAPI and no encryption. + * Test binding to the server using GSSAPI auth and no encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") - public void testSaslGssapiBindPlain( TestLdapServer ldapServer ) + public void testSaslGssapiBindAuthPlain( TestLdapServer ldapServer ) + { + testSaslGssapiBindPlain( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using GSSAPI auth-int and no encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthIntPlain( TestLdapServer ldapServer ) + { + testSaslGssapiBindPlain( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using GSSAPI auth-conf and no encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthConfPlain( TestLdapServer ldapServer ) + { + testSaslGssapiBindPlain( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslGssapiBindPlain( TestLdapServer ldapServer, SaslQoP saslQoP ) { TestFixture.skipIfKdcServerIsNotAvailable(); @@ -504,6 +618,7 @@ public void testSaslGssapiBindPlain( TestLdapServer ldapServer ) Connection connection = getConnection( monitor, ldapServer, "hnelson", "secret" ); connection.setAuthMethod( AuthenticationMethod.SASL_GSSAPI ); connection.getConnectionParameter().setKrb5CredentialConfiguration( Krb5CredentialConfiguration.OBTAIN_TGT ); + connection.getConnectionParameter().setSaslQop( saslQoP ); assertFalse( connectionWrapper.isConnected() ); @@ -521,11 +636,39 @@ public void testSaslGssapiBindPlain( TestLdapServer ldapServer ) /** - * Test binding to the server using GSSAPI and ldaps:// encryption. + * Test binding to the server using GSSAPI auth and ldaps:// encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthLdaps( TestLdapServer ldapServer ) throws Exception + { + testSaslGssapiBindLdaps( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using GSSAPI auth-int and ldaps:// encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthIntLdaps( TestLdapServer ldapServer ) throws Exception + { + testSaslGssapiBindLdaps( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using GSSAPI auth-conf and ldaps:// encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") - public void testSaslGssapiBindLdaps( TestLdapServer ldapServer ) throws Exception + public void testSaslGssapiBindAuthConfLdaps( TestLdapServer ldapServer ) throws Exception + { + testSaslGssapiBindLdaps( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslGssapiBindLdaps( TestLdapServer ldapServer, SaslQoP saslQoP ) throws Exception { TestFixture.skipIfKdcServerIsNotAvailable(); @@ -543,6 +686,7 @@ public void testSaslGssapiBindLdaps( TestLdapServer ldapServer ) throws Exceptio connection.setEncryptionMethod( EncryptionMethod.LDAPS ); connection.setAuthMethod( AuthenticationMethod.SASL_GSSAPI ); connection.getConnectionParameter().setKrb5CredentialConfiguration( Krb5CredentialConfiguration.USE_NATIVE ); + connection.getConnectionParameter().setSaslQop( saslQoP ); acceptAllCertificates(); assertFalse( connectionWrapper.isConnected() ); @@ -561,11 +705,39 @@ public void testSaslGssapiBindLdaps( TestLdapServer ldapServer ) throws Exceptio /** - * Test binding to the server using GSSAPI and StartTLS encryption. + * Test binding to the server using GSSAPI auth and StartTLS encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthStartTls( TestLdapServer ldapServer ) + { + testSaslGssapiBindStartTls( ldapServer, SaslQoP.AUTH ); + } + + + /** + * Test binding to the server using GSSAPI auth-int and StartTLS encryption. */ @ParameterizedTest @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") - public void testSaslGssapiBindStartTls( TestLdapServer ldapServer ) + public void testSaslGssapiBindAuthIntStartTls( TestLdapServer ldapServer ) + { + testSaslGssapiBindStartTls( ldapServer, SaslQoP.AUTH_INT ); + } + + + /** + * Test binding to the server using GSSAPI auth-conf and StartTLS encryption. + */ + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testSaslGssapiBindAuthConfStartTls( TestLdapServer ldapServer ) + { + testSaslGssapiBindStartTls( ldapServer, SaslQoP.AUTH_CONF ); + } + + + private void testSaslGssapiBindStartTls( TestLdapServer ldapServer, SaslQoP saslQoP ) { TestFixture.skipIfKdcServerIsNotAvailable(); @@ -575,6 +747,7 @@ public void testSaslGssapiBindStartTls( TestLdapServer ldapServer ) connection.setEncryptionMethod( EncryptionMethod.START_TLS ); connection.setAuthMethod( AuthenticationMethod.SASL_GSSAPI ); connection.getConnectionParameter().setKrb5CredentialConfiguration( Krb5CredentialConfiguration.OBTAIN_TGT ); + connection.getConnectionParameter().setSaslQop( saslQoP ); acceptAllCertificates(); assertFalse( connectionWrapper.isConnected() ); diff --git a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/OpenLdapServer.java b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/OpenLdapServer.java index 5a1e97102..0fd4ff6a4 100644 --- a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/OpenLdapServer.java +++ b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/OpenLdapServer.java @@ -21,8 +21,6 @@ package org.apache.directory.studio.test.integration.junit5; -import static org.apache.directory.studio.test.integration.junit5.Constants.LOCALHOST; - import org.apache.directory.api.ldap.model.entry.DefaultModification; import org.apache.directory.api.ldap.model.entry.Modification; import org.apache.directory.api.ldap.model.entry.ModificationOperation; @@ -88,12 +86,28 @@ public void prepare() @Override public void setConfidentialityRequired( boolean confidentialityRequired ) { + if ( confidentialityRequired ) + { + setSecurityProps( 256, 256 ); + } + else + { + setSecurityProps( 0, 0 ); + } + } + + + public void setSecurityProps( int ssf, int tls ) + { + try ( LdapConnection connection = openConnection() ) { connection.bind( OPENLDAP_CONFIG_DN, OPENLDAP_CONFIG_PASSWORD ); - Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, - "olcSecurity", confidentialityRequired ? "ssf=256 tls=256" : "ssf=0 tls=0" ); - connection.modify( "cn=config", modification ); + Modification modification1 = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, + "olcSecurity", "ssf=" + ssf + " tls=" + tls ); + Modification modification2 = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, + "olcSaslSecProps", "noplain,noanonymous,minssf=" + ssf ); + connection.modify( "cn=config", modification1, modification2 ); } catch ( LdapNoSuchAttributeException e ) { diff --git a/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif b/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif index 158317fa6..c9cdc8f70 100644 --- a/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif +++ b/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif @@ -21,7 +21,8 @@ replace: olcAccess olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external ,cn=auth manage by * break olcAccess: {1}to dn.exact="" by * read -olcAccess: {2}to dn.base="cn=Subschema" by dn.exact="uid=user.1,ou=users,dc=example,dc=org" none by * read +# Forbid user.8 to read the schema, used in SchemaBrowserTest +olcAccess: {2}to dn.base="cn=Subschema" by dn.exact="uid=user.8,ou=users,dc=example,dc=org" none by * read - dn: olcDatabase={1}mdb,cn=config diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/AbstractTestBase.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/AbstractTestBase.java index 817847ff2..7978ed9df 100644 --- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/AbstractTestBase.java +++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/AbstractTestBase.java @@ -32,6 +32,8 @@ import org.apache.directory.api.ldap.model.name.Dn; import org.apache.directory.api.ldap.model.name.Rdn; import org.apache.directory.studio.connection.core.ConnectionCorePlugin; +import org.apache.directory.studio.ldapbrowser.core.BrowserCoreConstants; +import org.apache.directory.studio.ldapbrowser.core.BrowserCorePlugin; import org.apache.directory.studio.test.integration.junit5.SkipTestIfLdapServerIsNotAvailableInterceptor; import org.apache.directory.studio.test.integration.junit5.TestLdapServer; import org.apache.directory.studio.test.integration.ui.bots.ApacheDSServersViewBot; @@ -72,6 +74,8 @@ final void setUpBase() throws Exception searchLogsViewBot = studioBot.getSearchLogsViewBot(); modificationLogsViewBot = studioBot.getModificationLogsViewBot(); serversViewBot = studioBot.getApacheDSServersViewBot(); + BrowserCorePlugin.getDefault() + .getPluginPreferences().setValue( BrowserCoreConstants.PREFERENCE_LDIF_LINE_WIDTH, 1000 ); } diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java index 4785dd7bc..43f21dfd7 100644 --- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java +++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java @@ -32,6 +32,7 @@ import java.lang.reflect.Method; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Arrays; import org.apache.directory.api.ldap.model.constants.SaslQoP; import org.apache.directory.api.ldap.model.constants.SaslSecurityStrength; @@ -40,9 +41,14 @@ import org.apache.directory.studio.connection.core.ConnectionManager; import org.apache.directory.studio.connection.core.ConnectionParameter.AuthenticationMethod; import org.apache.directory.studio.connection.core.ConnectionParameter.EncryptionMethod; +import org.apache.directory.studio.ldapbrowser.core.BrowserConnectionManager; +import org.apache.directory.studio.ldapbrowser.core.BrowserCorePlugin; +import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection; +import org.apache.directory.studio.ldapbrowser.core.model.IRootDSE; import org.apache.directory.studio.test.integration.junit5.LdapServerType; import org.apache.directory.studio.test.integration.junit5.LdapServersSource; import org.apache.directory.studio.test.integration.junit5.LdapServersSource.Mode; +import org.apache.directory.studio.test.integration.junit5.OpenLdapServer; import org.apache.directory.studio.test.integration.junit5.TestFixture; import org.apache.directory.studio.test.integration.junit5.TestLdapServer; import org.apache.directory.studio.test.integration.ui.bots.CertificateTrustDialogBot; @@ -373,7 +379,7 @@ public void testCreateConnectionNoEncryptionNoAuthInvalidHostname( TestLdapServe @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionNoEncryptionSimpleAuthOK( TestLdapServer server ) throws UnknownHostException { // enter connection parameter @@ -414,7 +420,6 @@ public void testCreateConnectionNoEncryptionSimpleAuthOK( TestLdapServer server @ParameterizedTest @LdapServersSource(mode = Mode.All) public void testCreateConnectionNoEncryptionSimpleAuthConfidentialityRequired( TestLdapServer server ) - { setConnectionParameters( server, EncryptionMethod.NONE ); @@ -433,7 +438,7 @@ public void testCreateConnectionNoEncryptionSimpleAuthConfidentialityRequired( T @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionNoEncryptionSaslCramMd5OK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.NONE ); @@ -453,8 +458,8 @@ public void testCreateConnectionNoEncryptionSaslCramMd5OK( TestLdapServer server @ParameterizedTest - @LdapServersSource(mode = Mode.All) - public void testCreateConnectionNoEncryptionSaslDigestMd5OK( TestLdapServer server ) + @LdapServersSource + public void testCreateConnectionNoEncryptionSaslDigestMd5AuthOK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.NONE ); @@ -473,7 +478,69 @@ public void testCreateConnectionNoEncryptionSaslDigestMd5OK( TestLdapServer serv @ParameterizedTest - @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds, reason = "Only secure binds configured for 389ds") + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Bug in SASL filter in ApacheDS 2.0.0.M26") + public void testCreateConnectionNoEncryptionSaslDigestMd5AuthIntOK( TestLdapServer server ) + { + // Configure OpenLDAP with ssf=1 (1 implies integrity protection only) + if ( server instanceof OpenLdapServer ) + { + OpenLdapServer openLdapServer = ( OpenLdapServer ) server; + openLdapServer.setSecurityProps( 1, 0 ); + } + + setConnectionParameters( server, EncryptionMethod.NONE ); + + wizardBot.selectDigestMD5Authentication(); + wizardBot.typeUser( "user.1" ); + wizardBot.typePassword( "password" ); + if ( server.getType() == LdapServerType.ApacheDS ) + { + wizardBot.typeRealm( "EXAMPLE.ORG" ); + } + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_INT ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.NONE, AuthenticationMethod.SASL_DIGEST_MD5, + "user.1", "password" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Bug in SASL filter in ApacheDS 2.0.0.M26.") + public void testCreateConnectionNoEncryptionSaslDigestMd5AuthConfOK( TestLdapServer server ) + { + // Configure OpenLDAP with ssf=128 (128 allows RC4, Blowfish and other modern strong ciphers) + if ( server instanceof OpenLdapServer ) + { + OpenLdapServer openLdapServer = ( OpenLdapServer ) server; + openLdapServer.setSecurityProps( 128, 0 ); + } + + setConnectionParameters( server, EncryptionMethod.NONE ); + + wizardBot.selectDigestMD5Authentication(); + wizardBot.typeUser( "user.1" ); + wizardBot.typePassword( "password" ); + if ( server.getType() == LdapServerType.ApacheDS ) + { + wizardBot.typeRealm( "EXAMPLE.ORG" ); + } + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.NONE, AuthenticationMethod.SASL_DIGEST_MD5, + "user.1", "password" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.Fedora389ds, reason = "Only secure binds configured for 389ds") public void testCreateConnectionNoEncryptionSaslDigestMd5ConfidentialityRequired( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.NONE ); @@ -491,8 +558,8 @@ public void testCreateConnectionNoEncryptionSaslDigestMd5ConfidentialityRequired @ParameterizedTest - @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") - public void testCreateConnectionNoEncryptionSaslGssapiNativeTgtOK( TestLdapServer server ) throws Exception + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionNoEncryptionSaslGssapiNativeTgtAuthOK( TestLdapServer server ) throws Exception { TestFixture.skipIfKdcServerIsNotAvailable(); @@ -520,8 +587,44 @@ public void testCreateConnectionNoEncryptionSaslGssapiNativeTgtOK( TestLdapServe @ParameterizedTest - @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") - public void testCreateConnectionNoEncryptionSaslGssapiObtainOK( TestLdapServer server ) + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionNoEncryptionSaslGssapiNativeTgtAuthConfOK( TestLdapServer server ) throws Exception + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + // Configure OpenLDAP with ssf=128 (128 allows RC4, Blowfish and other modern strong ciphers) + if ( server instanceof OpenLdapServer ) + { + OpenLdapServer openLdapServer = ( OpenLdapServer ) server; + openLdapServer.setSecurityProps( 128, 0 ); + } + + // obtain native TGT + String[] cmd = + { "/bin/sh", "-c", "echo secret | /usr/bin/kinit hnelson" }; + Process process = Runtime.getRuntime().exec( cmd ); + int exitCode = process.waitFor(); + assertEquals( 0, exitCode ); + + setConnectionParameters( server, EncryptionMethod.NONE ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + wizardBot.selectUseNativeTgt(); + wizardBot.selectUseNativeSystemConfiguration(); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.NONE, AuthenticationMethod.SASL_GSSAPI, + "", "" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionNoEncryptionSaslGssapiObtainAuthOK( TestLdapServer server ) { TestFixture.skipIfKdcServerIsNotAvailable(); @@ -543,7 +646,37 @@ public void testCreateConnectionNoEncryptionSaslGssapiObtainOK( TestLdapServer s @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionNoEncryptionSaslGssapiObtainAuthConfOK( TestLdapServer server ) + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + // Configure OpenLDAP with ssf=128 (128 allows RC4, Blowfish and other modern strong ciphers) + if ( server instanceof OpenLdapServer ) + { + OpenLdapServer openLdapServer = ( OpenLdapServer ) server; + openLdapServer.setSecurityProps( 128, 0 ); + } + + setConnectionParameters( server, EncryptionMethod.NONE ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectObtainTgtFromKdc(); + wizardBot.typeUser( "hnelson" ); + wizardBot.typePassword( "secret" ); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.NONE, AuthenticationMethod.SASL_GSSAPI, + "hnelson", "secret" ); + } + + + @ParameterizedTest + @LdapServersSource public void testCreateConnectionLdapsEncryptionNoAuthOK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.LDAPS ); @@ -555,7 +688,7 @@ public void testCreateConnectionLdapsEncryptionNoAuthOK( TestLdapServer server ) @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionLdapsEncryptionSimpleAuthOK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.LDAPS ); @@ -586,8 +719,8 @@ public void testCreateConnectionLdapsEncryptionSimpleAuthInvalidCredentials( Tes @ParameterizedTest - @LdapServersSource(mode = Mode.All) - public void testCreateConnectionLdapsEncryptionSaslDigestMd5Ok( TestLdapServer server ) + @LdapServersSource + public void testCreateConnectionLdapsEncryptionSaslDigestMd5AuthOk( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.LDAPS ); @@ -602,6 +735,48 @@ public void testCreateConnectionLdapsEncryptionSaslDigestMd5Ok( TestLdapServer s } + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Bug in SASL filter in ApacheDS 2.0.0.M26.") + public void testCreateConnectionLdapsEncryptionSaslDigestMd5AuthIntOk( TestLdapServer server ) + { + setConnectionParameters( server, EncryptionMethod.LDAPS ); + + wizardBot.selectDigestMD5Authentication(); + wizardBot.typeUser( "user.1" ); + wizardBot.typePassword( "password" ); + if ( server.getType() == LdapServerType.ApacheDS ) + { + wizardBot.typeRealm( "EXAMPLE.ORG" ); + } + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_INT ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + finishAndAssertConnection( server, EncryptionMethod.LDAPS, AuthenticationMethod.SASL_DIGEST_MD5, + "user.1", "password" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Bug in SASL filter in ApacheDS 2.0.0.M26.") + public void testCreateConnectionLdapsEncryptionSaslDigestMd5AuthConfOk( TestLdapServer server ) + { + setConnectionParameters( server, EncryptionMethod.LDAPS ); + + wizardBot.selectDigestMD5Authentication(); + wizardBot.typeUser( "user.1" ); + wizardBot.typePassword( "password" ); + if ( server.getType() == LdapServerType.ApacheDS ) + { + wizardBot.typeRealm( "EXAMPLE.ORG" ); + } + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + finishAndAssertConnection( server, EncryptionMethod.LDAPS, AuthenticationMethod.SASL_DIGEST_MD5, + "user.1", "password" ); + } + + @ParameterizedTest @LdapServersSource(mode = Mode.All) public void testCreateConnectionLdapsEncryptionSaslDigestMd5InvalidCredentials( TestLdapServer server ) @@ -642,7 +817,7 @@ public void testCreateConnectionLdapsEncryptionSaslDigestMd5InvalidRealm( TestLd @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionStartTlsEncryptionNoAuthOK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.START_TLS ); @@ -654,7 +829,7 @@ public void testCreateConnectionStartTlsEncryptionNoAuthOK( TestLdapServer serve @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionStartTlsEncryptionSimpleAuthOK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.START_TLS ); @@ -685,7 +860,7 @@ public void testCreateConnectionStartTlsEncryptionSimpleAuthInvalidCredentials( @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCreateConnectionStartTlsEncryptionSaslDigestMd5OK( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.START_TLS ); @@ -721,7 +896,165 @@ public void testCreateConnectionStartTlsEncryptionSaslDigestMd5InvalidCredential @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiNativeTgtAuthOK( TestLdapServer server ) + throws Exception + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + // obtain native TGT + String[] cmd = + { "/bin/sh", "-c", "echo secret | /usr/bin/kinit hnelson" }; + Process process = Runtime.getRuntime().exec( cmd ); + int exitCode = process.waitFor(); + assertEquals( 0, exitCode ); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + wizardBot.selectUseNativeTgt(); + wizardBot.selectUseNativeSystemConfiguration(); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.START_TLS, AuthenticationMethod.SASL_GSSAPI, + "", "" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiNativeTgtAuthConfOK( TestLdapServer server ) + throws Exception + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + // obtain native TGT + String[] cmd = + { "/bin/sh", "-c", "echo secret | /usr/bin/kinit hnelson" }; + Process process = Runtime.getRuntime().exec( cmd ); + int exitCode = process.waitFor(); + assertEquals( 0, exitCode ); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + wizardBot.selectUseNativeTgt(); + wizardBot.selectUseNativeSystemConfiguration(); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.START_TLS, AuthenticationMethod.SASL_GSSAPI, + "", "" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiNativeTgtAuthConfInvalidCredentials( + TestLdapServer server ) throws Exception + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + // obtain native TGT + String[] cmd = + { "/bin/sh", "-c", "echo secret | /usr/bin/kdestroy -A" }; + Process process = Runtime.getRuntime().exec( cmd ); + int exitCode = process.waitFor(); + assertEquals( 0, exitCode ); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + wizardBot.selectUseNativeTgt(); + wizardBot.selectUseNativeSystemConfiguration(); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertThat( result, containsString( "Unable to obtain Principal Name for authentication" ) ); + + finishAndAssertConnectionError( "Unable to obtain Principal Name for authentication" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiObtainAuthOK( TestLdapServer server ) + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectObtainTgtFromKdc(); + wizardBot.typeUser( "hnelson" ); + wizardBot.typePassword( "secret" ); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.START_TLS, AuthenticationMethod.SASL_GSSAPI, + "hnelson", "secret" ); + } + + + @ParameterizedTest + @LdapServersSource(except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiObtainAuthConfOK( TestLdapServer server ) + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectObtainTgtFromKdc(); + wizardBot.typeUser( "hnelson" ); + wizardBot.typePassword( "secret" ); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertNull( result, "Expected OK" ); + + finishAndAssertConnection( server, EncryptionMethod.START_TLS, AuthenticationMethod.SASL_GSSAPI, + "hnelson", "secret" ); + } + + + @ParameterizedTest + @LdapServersSource(mode = Mode.All, except = LdapServerType.ApacheDS, reason = "Missing OSGi import: org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntryModifier cannot be found by org.apache.directory.server.protocol.shared_2.0.0.AM26") + public void testCreateConnectionStartTlsEncryptionSaslGssapiObtainAuthConfInvalidCredentials( + TestLdapServer server ) + { + TestFixture.skipIfKdcServerIsNotAvailable(); + + setConnectionParameters( server, EncryptionMethod.START_TLS ); + + wizardBot.selectGssApiAuthentication(); + wizardBot.selectObtainTgtFromKdc(); + wizardBot.typeUser( "hnelson" ); + wizardBot.typePassword( "invalid" ); + wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF ); + wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH ); + + String result = wizardBot.clickCheckAuthenticationButton(); + assertThat( result, containsString( "Integrity check on decrypted field failed (31) - PREAUTH_FAILED" ) ); + + finishAndAssertConnectionError( "Integrity check on decrypted field failed (31) - PREAUTH_FAILED" ); + } + + + @ParameterizedTest + @LdapServersSource public void testCheckNetworkParameterButtonNoEncryptionNotOk( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.NONE ); @@ -744,7 +1077,7 @@ public void testCheckNetworkParameterButtonNoEncryptionNotOk( TestLdapServer ser @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCheckNetworkParameterButtonLdapsEncryptionNotOk( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.LDAPS ); @@ -772,7 +1105,7 @@ public void testCheckNetworkParameterButtonLdapsEncryptionNotOk( TestLdapServer @ParameterizedTest - @LdapServersSource(mode = Mode.All) + @LdapServersSource public void testCheckNetworkParameterButtonStartTlsEncryptionNotOk( TestLdapServer server ) { setConnectionParameters( server, EncryptionMethod.START_TLS ); @@ -860,6 +1193,16 @@ private void finishAndAssertConnection( TestLdapServer server, EncryptionMethod // ensure connection is visible in Connections view assertEquals( 1, connectionsViewBot.getCount() ); + // assert Root DSE and schema was read + BrowserConnectionManager browserConnectionManager = BrowserCorePlugin.getDefault().getConnectionManager(); + IBrowserConnection browserConnection = browserConnectionManager.getBrowserConnection( connection ); + IRootDSE rootDSE = browserConnection.getRootDSE(); + assertTrue( Arrays.asList( rootDSE.getAttribute( "namingContexts" ).getStringValues() ) + .contains( TestFixture.CONTEXT_DN.getName() ) ); + assertFalse( browserConnection.getSchema().isDefault() ); + assertTrue( browserConnection.getSchema().getObjectClassDescriptions().size() > 50 ); + assertTrue( browserConnection.getSchema().getAttributeTypeDescriptions().size() > 100 ); + // close connection connectionsViewBot.closeSelectedConnections(); } diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/SchemaBrowserTest.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/SchemaBrowserTest.java index e8c0e04fb..625cfd1a1 100644 --- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/SchemaBrowserTest.java +++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/SchemaBrowserTest.java @@ -21,7 +21,7 @@ package org.apache.directory.studio.test.integration.ui; -import static org.apache.directory.studio.test.integration.junit5.TestFixture.USER1_DN; +import static org.apache.directory.studio.test.integration.junit5.TestFixture.USER8_DN; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -77,8 +77,8 @@ public void testNoPermissionToReadSchema( TestLdapServer server ) throws Excepti .getBrowserConnection( connection ); browserConnection.setSchema( Schema.DEFAULT_SCHEMA ); - // Open connection as uid=user.1 which is not allowed to read cn=subschema - connection.setBindPrincipal( USER1_DN.getName() ); + // Open connection as uid=user.8 which is not allowed to read cn=subschema + connection.setBindPrincipal( USER8_DN.getName() ); connection.setBindPassword( "password" ); ErrorDialogBot errorDialog = connectionsViewBot.openSelectedConnectionExpectingNoSchemaProvidedErrorDialog(); assertThat( errorDialog.getErrorDetails(), diff --git a/tools/testlab/README.md b/tools/testlab/README.md index 288766fcc..b3980d8a5 100644 --- a/tools/testlab/README.md +++ b/tools/testlab/README.md @@ -63,7 +63,7 @@ ldapwhoami -H ldap://fedora389ds.example.com:21389 -Y GSSAPI -N ### UI integration tests ``` -docker run -it --rm --cpus="1.5" \ +docker run -it --rm \ -u $(id -u):$(id -g) \ -v ~/.m2:/home/hnelson/.m2 \ -v $(pwd):/home/hnelson/project \