View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2015-2016 ForgeRock AS.
15   */
16  package org.forgerock.selfservice.example;
17  
18  import static org.forgerock.json.JsonValue.field;
19  import static org.forgerock.json.JsonValue.json;
20  import static org.forgerock.json.JsonValue.object;
21  import static org.forgerock.json.resource.Responses.newActionResponse;
22  import static org.wrensecurity.guava.common.base.Strings.isNullOrEmpty;
23  
24  import jakarta.mail.Authenticator;
25  import jakarta.mail.Message;
26  import jakarta.mail.MessagingException;
27  import jakarta.mail.PasswordAuthentication;
28  import jakarta.mail.Session;
29  import jakarta.mail.Transport;
30  import jakarta.mail.internet.InternetAddress;
31  import jakarta.mail.internet.MimeMessage;
32  import java.util.Properties;
33  import org.forgerock.json.JsonValue;
34  import org.forgerock.json.resource.ActionRequest;
35  import org.forgerock.json.resource.ActionResponse;
36  import org.forgerock.json.resource.BadRequestException;
37  import org.forgerock.json.resource.InternalServerErrorException;
38  import org.forgerock.json.resource.NotSupportedException;
39  import org.forgerock.json.resource.PatchRequest;
40  import org.forgerock.json.resource.ReadRequest;
41  import org.forgerock.json.resource.ResourceException;
42  import org.forgerock.json.resource.ResourceResponse;
43  import org.forgerock.json.resource.SingletonResourceProvider;
44  import org.forgerock.json.resource.UpdateRequest;
45  import org.forgerock.services.context.Context;
46  import org.forgerock.util.Reject;
47  import org.forgerock.util.promise.Promise;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  /**
52   * Example email service.
53   *
54   * @since 0.1.0
55   */
56  final class ExampleEmailService implements SingletonResourceProvider {
57  
58      private static final Logger LOGGER = LoggerFactory.getLogger(ExampleEmailService.class);
59  
60      private final String host;
61      private final String port;
62      private final String username;
63      private final String password;
64  
65      ExampleEmailService(JsonValue config) {
66          host = config.get("host").required().asString();
67          port = config.get("port").required().asString();
68          username = System.getProperty("mailserver.username");
69          password = System.getProperty("mailserver.password");
70          Reject.ifNull(username, password);
71      }
72  
73      @Override
74      public Promise<ActionResponse, ResourceException> actionInstance(Context context, ActionRequest request) {
75          if (request.getAction().equals("send")) {
76              try {
77                  JsonValue response = sendEmail(request.getContent());
78                  return newActionResponse(response).asPromise();
79              } catch (ResourceException rE) {
80                  return rE.asPromise();
81              }
82          }
83  
84          return new NotSupportedException("Unknown action " + request.getAction()).asPromise();
85      }
86  
87      private JsonValue sendEmail(JsonValue document) throws ResourceException {
88          String to = document.get("to").asString();
89  
90          if (isNullOrEmpty(to)) {
91              throw new BadRequestException("Field to is not specified");
92          }
93  
94          String from = document.get("from").asString();
95  
96          if (isNullOrEmpty(from)) {
97              throw new BadRequestException("Field from is not specified");
98          }
99  
100         String subject = document.get("subject").asString();
101 
102         if (isNullOrEmpty(subject)) {
103             throw new BadRequestException("Field subject is not specified");
104         }
105 
106         String messageBody = document.get("body").asString();
107 
108         if (isNullOrEmpty(messageBody)) {
109             throw new BadRequestException("Field message is not specified");
110         }
111 
112         Properties props = new Properties();
113         props.put("mail.smtp.auth", "true");
114         props.put("mail.smtp.starttls.enable", "true");
115         props.put("mail.smtp.host", host);
116         props.put("mail.smtp.port", port);
117 
118         Session session = Session.getInstance(props, new Authenticator() {
119 
120             @Override
121             protected PasswordAuthentication getPasswordAuthentication() {
122                 return new PasswordAuthentication(username, password);
123             }
124 
125         });
126 
127         try {
128             Message message = new MimeMessage(session);
129             message.setFrom(new InternetAddress(from));
130             message.setRecipients(Message.RecipientType.TO,
131                     InternetAddress.parse(to));
132             message.setSubject(subject);
133             message.setContent(messageBody, "text/html; charset=UTF-8");
134 
135             Transport.send(message);
136             LOGGER.debug("Email sent to " + to);
137 
138         } catch (MessagingException mE) {
139             throw new InternalServerErrorException(mE);
140         }
141 
142         return json(object(field("status", "okay")));
143     }
144 
145     @Override
146     public Promise<ResourceResponse, ResourceException> patchInstance(Context context, PatchRequest request) {
147         return new NotSupportedException().asPromise();
148     }
149 
150     @Override
151     public Promise<ResourceResponse, ResourceException> readInstance(Context context, ReadRequest request) {
152         return new NotSupportedException().asPromise();
153     }
154 
155     @Override
156     public Promise<ResourceResponse, ResourceException> updateInstance(Context context, UpdateRequest request) {
157         return new NotSupportedException().asPromise();
158     }
159 
160 }