You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/10/25 19:00:04 UTC

[camel-spring-boot-examples] branch main updated: Added Microsoft Exchange IMAP Oauth2 Authentication example (#96)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot-examples.git


The following commit(s) were added to refs/heads/main by this push:
     new 7858311  Added Microsoft Exchange IMAP Oauth2 Authentication example (#96)
7858311 is described below

commit 78583119d6cec15a89b2727bbf15fb109442aedd
Author: Luigi De Masi <55...@users.noreply.github.com>
AuthorDate: Tue Oct 25 20:59:58 2022 +0200

    Added Microsoft Exchange IMAP Oauth2 Authentication example (#96)
---
 mail-ms-exchange-oauth2/Readme.adoc                |  64 ++++++++++++
 mail-ms-exchange-oauth2/pom.xml                    | 111 +++++++++++++++++++++
 .../mail/oauth2/ApplicationConfiguration.java      | 109 ++++++++++++++++++++
 .../example/mail/oauth2/CamelApplication.java      |  64 ++++++++++++
 .../oauth2/Oauth2ExchangeMailAuthenticator.java    |  82 +++++++++++++++
 .../src/main/resources/application.properties      |  43 ++++++++
 pom.xml                                            |   1 +
 7 files changed, 474 insertions(+)

diff --git a/mail-ms-exchange-oauth2/Readme.adoc b/mail-ms-exchange-oauth2/Readme.adoc
new file mode 100644
index 0000000..f12c6ef
--- /dev/null
+++ b/mail-ms-exchange-oauth2/Readme.adoc
@@ -0,0 +1,64 @@
+== Camel Spring Boot Microsoft Exchange IMAP Oauth2 Authentication
+
+This is an example that shows how to use Camel on Spring Boot to connect with
+IMAP protocol and access email data for Office 365 users using OAuth2 authentication.
+
+The application will use the client credentials grant flow to get the access token
+and use it to authenticate IMAP connections.
+
+
+=== Prerequisite
+
+* To use OAuth, an application must be registered with Azure Active Directory.
+Follow the instructions listed in https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app[Register an application with the Microsoft identity platform] to register a new application.
+
+* Enable application to access Exchange mailboxes via client credentials flow adding *IMAP.AccessAsApp* permission. Instructions https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#add-the-pop-and-imap-permissions-to-your-aad-application[here]
+
+* Create and register your Azure Active Directory application's service principal
+in Exchange via Exchange Online PowerShell. Instructions https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#register-service-principals-in-exchange[here]
+
+* Edit the link:src/main/resources/application.properties[application.properties] adding the values to the properties marked with ``<FILL-ME>`` tag
+
+=== How to run
+
+You can run this example using:
+
+[source%nowrap, console]
+----
+mvn spring-boot:run
+----
+And you should see this output:
+
+[source%nowrap, console]
+----
+  .   ____          _            __ _ _
+ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
+  '  |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot ::                (v2.7.5)
+
+2022-10-24 19:19:58.705  INFO 2274709 --- [           main] o.a.c.e.mail.oauth2.CamelApplication     : Starting CamelApplication
+2022-10-24 19:19:58.707  INFO 2274709 --- [           main] o.a.c.e.mail.oauth2.CamelApplication     : No active profile set, falling back to 1 default profile: "default"
+2022-10-24 19:20:00.777  INFO 2274709 --- [           main] o.a.c.impl.engine.AbstractCamelContext   : Apache Camel is starting
+2022-10-24 19:20:00.785  INFO 2274709 --- [           main] c.s.b.CamelSpringBootApplicationListener : Starting CamelMainRunController to ensure the main thread keeps running
+2022-10-24 19:20:00.785  INFO 2274709 --- [inRunController] org.apache.camel.main.MainSupport        : Apache Camel (Main)  is starting
+2022-10-24 19:20:00.813  INFO 2274709 --- [           main] o.a.c.impl.engine.AbstractCamelContext   : Routes startup (started:1)
+2022-10-24 19:20:00.813  INFO 2274709 --- [           main] o.a.c.impl.engine.AbstractCamelContext   : Started camel-mail-ms-exchange (imaps://outlook.office365.com:993)
+2022-10-24 19:20:00.813  INFO 2274709 --- [           main] o.a.c.impl.engine.AbstractCamelContext   : Apache Camel (CamelMailExchangeOAuth2) started in 1s226ms (build:29ms init:1s163ms start:34ms)
+2022-10-24 19:20:00.819  INFO 2274709 --- [           main] o.a.c.e.mail.oauth2.CamelApplication     : Started CamelApplication in 2.407 seconds (JVM running for 2.883)
+2022-10-24 19:20:04.842  INFO 2274709 --- [fice365.com:993] camel-mail-ms-exchange                   : message Received:
+From: John Doe <jd...@example.com>
+Subj: Test
+Body:
+This is a Test!!!
+
+2022-10-24 19:20:05.167  INFO 2274709 --- [fice365.com:993] camel-mail-ms-exchange                   : message Received:
+From: Teigan Moore <te...@xyz.com>
+Subj: Prova
+Body:
+Prova Prova Prova
+--
+Teigan Moore
+----
\ No newline at end of file
diff --git a/mail-ms-exchange-oauth2/pom.xml b/mail-ms-exchange-oauth2/pom.xml
new file mode 100644
index 0000000..67b0b4b
--- /dev/null
+++ b/mail-ms-exchange-oauth2/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>examples</artifactId>
+        <groupId>org.apache.camel.springboot.example</groupId>
+        <version>3.20.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>camel-example-spring-boot-mail-exchange-oauth2</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel SB Examples :: Mail :: Microsoft Exchange Oauth2 Authentication</name>
+    <description>An example showing how to use Camel on Spring Boot to connect
+        with IMAP protocol and access email data for Office 365 users using OAuth2 authentication</description>
+
+    <properties>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+        <msal4j-version>1.13.2</msal4j-version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- Spring Boot BOM -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <!-- Camel BOM -->
+            <dependency>
+                <groupId>org.apache.camel.springboot</groupId>
+                <artifactId>camel-spring-boot-bom</artifactId>
+                <version>${camel-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- Spring Boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- Camel -->
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-mail-starter</artifactId>
+        </dependency>
+
+        <!--Microsoft Authentication Library for Java  -->
+        <dependency>
+            <groupId>com.microsoft.azure</groupId>
+            <artifactId>msal4j</artifactId>
+            <version>${msal4j-version}</version>
+        </dependency>
+
+    </dependencies>
+
+
+    <build>
+        <!-- we do not want version in the JAR name -->
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot-version}</version>
+                <configuration>
+                    <mainClass>
+                        org.apache.camel.example.mail.oauth2.CamelApplication
+                    </mainClass>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/ApplicationConfiguration.java b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/ApplicationConfiguration.java
new file mode 100644
index 0000000..5828fa5
--- /dev/null
+++ b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/ApplicationConfiguration.java
@@ -0,0 +1,109 @@
+/*
+ * 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.camel.example.mail.oauth2;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotEmpty;
+
+@Validated
+@Configuration
+@ConfigurationProperties(prefix = "exchange")
+public class ApplicationConfiguration {
+
+    @NotEmpty
+    private String tenantId;
+
+    @NotEmpty
+    private String clientId;
+
+    @NotEmpty
+    private String clientSecret;
+
+    @Email
+    @NotEmpty
+    private String user;
+
+    @Min(1)
+    private long pollInterval = 60000;
+
+    private boolean debug = false;
+
+    private boolean delete = false;
+
+
+
+    public String getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(String tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public long getPollInterval() {
+        return pollInterval;
+    }
+
+    public void setPollInterval(long pollInterval) {
+        this.pollInterval = pollInterval;
+    }
+
+    public boolean isDebug() {
+        return debug;
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public boolean isDelete() {
+        return delete;
+    }
+
+    public void setDelete(boolean delete) {
+        this.delete = delete;
+    }
+}
diff --git a/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/CamelApplication.java b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/CamelApplication.java
new file mode 100644
index 0000000..0e6a6a5
--- /dev/null
+++ b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/CamelApplication.java
@@ -0,0 +1,64 @@
+/*
+ * 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.camel.example.mail.oauth2;
+
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+
+@SpringBootApplication
+@EnableConfigurationProperties
+public class CamelApplication {
+
+    @Autowired
+    ApplicationConfiguration conf;
+
+    /**
+     * A main method to start this application.
+     */
+    public static void main(String[] args) {
+        SpringApplication.run(CamelApplication.class, args);
+    }
+
+    @Bean
+    public Oauth2ExchangeMailAuthenticator exchangeAuthenticator(){
+        return new Oauth2ExchangeMailAuthenticator(conf.getTenantId(),conf.getClientId(), conf.getClientSecret(), conf.getUser());
+    }
+
+    @Bean
+    public RouteBuilder routeBuilder(){
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("imaps://outlook.office365.com:993?" +
+                        "delay="+conf.getPollInterval()+"}&" +
+                        "authenticator=#exchangeAuthenticator&" +
+                        "mail.imaps.auth.mechanisms=XOAUTH2&" +
+                        "debugMode="+conf.isDebug()+"&" +
+                        "delete="+conf.isDelete()+"&"+
+                        "bridgeErrorHandler=true")
+                        .id("camel-mail-ms-exchange")
+                        .log(LoggingLevel.INFO, "message Received: \nFrom: ${header.from}\nSubj: ${header.subject}\nBody:\n${body}");
+            }
+        };
+    }
+}
diff --git a/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/Oauth2ExchangeMailAuthenticator.java b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/Oauth2ExchangeMailAuthenticator.java
new file mode 100644
index 0000000..b0eac99
--- /dev/null
+++ b/mail-ms-exchange-oauth2/src/main/java/org/apache/camel/example/mail/oauth2/Oauth2ExchangeMailAuthenticator.java
@@ -0,0 +1,82 @@
+/*
+ * 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.camel.example.mail.oauth2;
+
+import com.microsoft.aad.msal4j.ClientCredentialFactory;
+import com.microsoft.aad.msal4j.ClientCredentialParameters;
+import com.microsoft.aad.msal4j.ConfidentialClientApplication;
+import com.microsoft.aad.msal4j.IAuthenticationResult;
+import com.microsoft.aad.msal4j.IClientCredential;
+import org.apache.camel.component.mail.MailAuthenticator;
+
+import javax.mail.PasswordAuthentication;
+import java.net.MalformedURLException;
+import java.util.Collections;
+import java.util.Set;
+
+
+public class Oauth2ExchangeMailAuthenticator extends MailAuthenticator {
+    private static final Set<String> SCOPE = Collections.singleton("https://outlook.office365.com/.default");
+    private static final String AUTHORITY_BASE_URL = "https://login.microsoftonline.com/";
+    private final String clientId;
+    private final String clientSecret;
+    private final String authority;
+    private final String user;
+
+
+    public Oauth2ExchangeMailAuthenticator(String tenantId, String clientId, String clientSecret, String user) {
+        this.clientId = clientId;
+        this.clientSecret = clientSecret;
+        this.authority = AUTHORITY_BASE_URL + tenantId;
+        this.user = user;
+    }
+
+    @Override
+    public PasswordAuthentication getPasswordAuthentication() {
+           String accessToken = acquireToken();
+            return new PasswordAuthentication(user, accessToken);
+    }
+
+    private String acquireToken() {
+
+        ConfidentialClientApplication cca;
+        try {
+            // This is the secret that is created in the Azure portal when registering the application
+            IClientCredential credential = ClientCredentialFactory.createFromSecret(clientSecret);
+
+            cca = ConfidentialClientApplication
+                    .builder(clientId, credential)
+                    .authority(authority)
+                    .build();
+        } catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
+
+        // Client credential requests will by default try to look for a valid token in the
+        // in-memory token cache. If found, it will return this token. If a token is not found, or the
+        // token is not valid, it will fall back to acquiring a token from the AAD service. Although
+        // not recommended unless there is a reason for doing so, you can skip the cache lookup
+        // by using .skipCache(true) in ClientCredentialParameters.
+        ClientCredentialParameters parameters =
+                ClientCredentialParameters
+                        .builder(SCOPE)
+                        .build();
+
+        IAuthenticationResult result = cca.acquireToken(parameters).join();
+        return result.accessToken();
+    }
+}
diff --git a/mail-ms-exchange-oauth2/src/main/resources/application.properties b/mail-ms-exchange-oauth2/src/main/resources/application.properties
new file mode 100644
index 0000000..84446b0
--- /dev/null
+++ b/mail-ms-exchange-oauth2/src/main/resources/application.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+camel.springboot.name: CamelMailExchangeOAuth2
+
+# Keep the application running
+camel.springboot.main-run-controller: true
+
+
+# Azure Active Directory tenant ID
+exchange.tenantId=<FILL-ME>
+
+# Azure Active Directory client credentials
+exchange.clientId=<FILL-ME>
+
+# Azure Active Directory client secret
+exchange.clientSecret=<FILL-ME>
+
+# Microsoft Exchange Username. Must be an email.
+exchange.user=<FILL-ME>
+
+# Milliseconds between two poll.
+exchange.pollInterval=60000
+
+# Enable javax.mail verbose output
+exchange.debug=false
+
+# Delete message after consuming it
+exchange.delete=false
diff --git a/pom.xml b/pom.xml
index b246620..9baca7d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,7 @@
 		<module>kafka-offsetrepository</module>
 		<module>kamelet-chucknorris</module>
 		<module>load-balancer-eip</module>
+		<module>mail-ms-exchange-oauth2</module>
 		<module>master</module>
 		<module>metrics</module>
 		<module>opentracing</module>