Skip to content

Commit 5bac04d

Browse files
authored
Merge pull request #4801 from nverwer/feature/6.x.x-mail-session-authentication
[6.x.x] Add mail:get-mail-session#2 with authentication
2 parents 0b4ce1e + 9df775a commit 5bac04d

File tree

3 files changed

+101
-24
lines changed

3 files changed

+101
-24
lines changed

extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailModule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class MailModule extends AbstractInternalModule {
7171

7272
private final static FunctionDef[] functions = {
7373
new FunctionDef(MailSessionFunctions.signatures[0], MailSessionFunctions.class),
74+
new FunctionDef(MailSessionFunctions.signatures[1], MailSessionFunctions.class),
7475
new FunctionDef(MailStoreFunctions.signatures[0], MailStoreFunctions.class),
7576
new FunctionDef(MailStoreFunctions.signatures[1], MailStoreFunctions.class),
7677
new FunctionDef(MailFolderFunctions.signatures[0], MailFolderFunctions.class),

extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailSessionFunctions.java

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
import java.util.Properties;
2626

27+
import jakarta.mail.Authenticator;
28+
import jakarta.mail.PasswordAuthentication;
2729
import jakarta.mail.Session;
2830

2931
import org.apache.logging.log4j.LogManager;
@@ -43,6 +45,8 @@
4345
import org.exist.xquery.value.SequenceType;
4446
import org.exist.xquery.value.Type;
4547

48+
import org.w3c.dom.Element;
49+
4650
/**
4751
* eXist Mail Module Extension GetSession
4852
*
@@ -68,28 +72,61 @@ public class MailSessionFunctions extends BasicFunction
6872
new FunctionParameterSequenceType( "properties", Type.ELEMENT, Cardinality.ZERO_OR_ONE, "An optional JavaMail session properties in the form <properties><property name=\"\" value=\"\"/></properties>. The JavaMail properties are spelled out in Appendix A of the JavaMail specifications." )
6973
},
7074
new FunctionReturnSequenceType( Type.LONG, Cardinality.ZERO_OR_ONE, "an xs:long representing the session handle." )
71-
)
75+
),
76+
77+
new FunctionSignature(
78+
new QName( "get-mail-session", MailModule.NAMESPACE_URI, MailModule.PREFIX ),
79+
"Opens a JavaMail session with authentication.",
80+
new SequenceType[]
81+
{
82+
new FunctionParameterSequenceType( "properties", Type.ELEMENT, Cardinality.ZERO_OR_ONE, "An optional JavaMail session properties in the form <properties><property name=\"\" value=\"\"/></properties>. The JavaMail properties are spelled out in Appendix A of the JavaMail specifications." ),
83+
new FunctionParameterSequenceType( "authentication", Type.ELEMENT, Cardinality.EXACTLY_ONE, "The username and password for authentication in the form <authentication username=\"\" password=\"\"/>." )
84+
},
85+
new FunctionReturnSequenceType( Type.LONG, Cardinality.ZERO_OR_ONE, "an xs:long representing the session handle." )
86+
)
7287
};
7388

7489
public MailSessionFunctions( XQueryContext context, FunctionSignature signature )
7590
{
7691
super( context, signature );
7792
}
7893

79-
@Override
80-
public Sequence eval( Sequence[] args, Sequence contextSequence ) throws XPathException
81-
{
82-
Properties props = new Properties();
83-
84-
if( args.length == 1 ) {
85-
// try and get the session properties
86-
props = ParametersExtractor.parseProperties( ((NodeValue) args[0].itemAt(0)).getNode() );
94+
@Override
95+
public Sequence eval( Sequence[] args, Sequence contextSequence ) throws XPathException
96+
{
97+
Properties props = new Properties();
98+
99+
if( args.length > 0 ) {
100+
// try and get the session properties
101+
props = ParametersExtractor.parseProperties( ((NodeValue) args[0].itemAt(0)).getNode() );
102+
}
103+
104+
Authenticator auth = null;
105+
106+
if( args.length > 1 ) {
107+
// get the authentication parameters
108+
Element authElement = (Element) ((NodeValue) args[1].itemAt(0)).getNode();
109+
if( authElement != null ) {
110+
String username = authElement.getAttribute("username");
111+
String password = authElement.getAttribute("password");
112+
if( username != null && password != null ) {
113+
auth = new Authenticator() {
114+
@Override
115+
protected PasswordAuthentication getPasswordAuthentication() {
116+
return new PasswordAuthentication(username, password);
117+
}
118+
};
119+
} else {
120+
throw new IllegalArgumentException("'username' and 'password' attributes are mandatory in the 'authentication' element");
121+
}
122+
} else {
123+
throw new IllegalArgumentException("'authentication' element missing");
124+
}
125+
}
126+
127+
Session session = Session.getInstance( props, auth );
128+
129+
// store the session and return the handle of the session
130+
return new IntegerValue( this, MailModule.storeSession( context, session ), Type.LONG );
87131
}
88-
89-
Session session = Session.getInstance( props, null );
90-
91-
// store the session and return the handle of the session
92-
93-
return new IntegerValue( this, MailModule.storeSession( context, session ) );
94132
}
95-
}

extensions/modules/mail/src/test/java/org/exist/xquery/modules/mail/SendEmailIT.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.exist.xmldb.XmldbURI;
5959
import org.exist.xquery.XPathException;
6060
import org.exist.xquery.value.Sequence;
61+
import org.junit.Before;
6162
import org.junit.BeforeClass;
6263
import org.junit.ClassRule;
6364
import org.junit.Rule;
@@ -68,7 +69,7 @@
6869

6970
import javax.annotation.Nullable;
7071
import java.io.IOException;
71-
import java.util.EnumSet;
72+
import java.util.Arrays;
7273
import java.util.Optional;
7374

7475
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -90,14 +91,26 @@ enum SmtpImplementation {
9091
JAKARTA_MAIL
9192
}
9293

93-
@Parameterized.Parameters(name = "{0}")
94-
public static java.util.Collection<SmtpImplementation> data() {
95-
return EnumSet.allOf(SmtpImplementation.class);
94+
enum AuthenticationOption {
95+
NOT_AUTHENTICATED,
96+
AUTHENTICATED
9697
}
9798

98-
@Parameterized.Parameter
99+
@Parameterized.Parameters(name = "{0} {1}")
100+
public static java.util.Collection<Object[]> data() {
101+
return Arrays.asList(new Object[][] {
102+
{ SmtpImplementation.SMTP_DIRECT_CONNECTION, AuthenticationOption.NOT_AUTHENTICATED },
103+
{ SmtpImplementation.JAKARTA_MAIL, AuthenticationOption.NOT_AUTHENTICATED },
104+
{ SmtpImplementation.JAKARTA_MAIL, AuthenticationOption.AUTHENTICATED },
105+
});
106+
}
107+
108+
@Parameterized.Parameter(0)
99109
public SmtpImplementation smtpImplementation;
100110

111+
@Parameterized.Parameter(1)
112+
public AuthenticationOption authenticationOption;
113+
101114
@ClassRule
102115
public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, true);
103116

@@ -107,6 +120,9 @@ public static java.util.Collection<SmtpImplementation> data() {
107120
private static final XmldbURI BIN_DOC1_NAME = XmldbURI.create("doc 1.bin"); // NOTE(AR) intentionally contains a space character to test correct encoding/decoding
108121
private static final byte[] BIN_DOC1_CONTENT = UUIDGenerator.getUUIDversion4().getBytes(UTF_8);
109122

123+
private static final String EMAIL_UID = "emailuid";
124+
private static final String EMAIL_PWD = "emailpwd";
125+
110126
private final int smtpPort = nextFreePort(2525, 2599, 10);
111127

112128
@Rule
@@ -127,6 +143,13 @@ public static void setup() throws PermissionDeniedException, IOException, SAXExc
127143
}
128144
}
129145

146+
@Before
147+
public void setSmtpAuth() {
148+
if (authenticationOption == AuthenticationOption.AUTHENTICATED) {
149+
greenMail.setUser(EMAIL_UID, EMAIL_PWD);
150+
}
151+
}
152+
130153
@Test
131154
public void sendTextEmail() throws EXistException, XPathException, PermissionDeniedException, IOException, MessagingException {
132155
final String messageText = UUIDGenerator.getUUIDversion4();
@@ -528,6 +551,10 @@ private MimeMessage sendEmail(final String message, @Nullable final String[] att
528551
}
529552

530553
private MimeMessage sendEmailBySmtpDirectConnection(final String message, @Nullable final String[] attachmentPaths) throws EXistException, XPathException, PermissionDeniedException, IOException, MessagingException {
554+
if (authenticationOption == AuthenticationOption.AUTHENTICATED) {
555+
throw new UnsupportedOperationException("Authentication is not yet implemented by SMTP direct connection");
556+
}
557+
531558
final String from = "[email protected]";
532559
final String to = "[email protected]";
533560
final String subject = "some email subject";
@@ -601,7 +628,7 @@ private MimeMessage sendEmailByJakartaMail(final String message, final String[]
601628
tmpAttachmentPaths = "'" + tmpAttachmentPaths + "'";
602629
}
603630

604-
final String query =
631+
String query =
605632
"import module namespace mail = \"http://exist-db.org/xquery/mail\";\n" +
606633
"let $attachments := \n" +
607634
" for $attachment-path in (" + tmpAttachmentPaths + ")\n" +
@@ -619,8 +646,20 @@ private MimeMessage sendEmailByJakartaMail(final String message, final String[]
619646
" <properties>\n" +
620647
" <property name=\"mail.transport.protocol\" value=\"smtp\"/>\n" +
621648
" <property name=\"mail.smtp.port\" value=\"" + smtpPort + "\"/>\n" +
622-
" <property name=\"mail.smtp.host\" value=\"127.0.0.1\"/>\n" +
623-
" </properties>\n" +
649+
" <property name=\"mail.smtp.host\" value=\"127.0.0.1\"/>\n";
650+
651+
if (authenticationOption == AuthenticationOption.AUTHENTICATED) {
652+
query +=
653+
" <property name=\"mail.smtp.auth\" value=\"true\"/>" +
654+
" </properties>\n" +
655+
", \n" +
656+
"<authentication username='" + EMAIL_UID + "' password='" + EMAIL_PWD + "'/>";
657+
} else {
658+
query +=
659+
" </properties>\n";
660+
}
661+
662+
query +=
624663
")\n" +
625664
" return\n" +
626665
" mail:send-email(\n" +

0 commit comments

Comments
 (0)