Browse Source

implemented:

- altering of mail settings
- sending email

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 4 months ago
parent
commit
31afced7f7
  1. 1
      de.srsoftware.oidc.api/build.gradle
  2. 3
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java
  3. 8
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/MailConfig.java
  4. 26
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/EmailController.java
  5. 9
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java
  6. 1
      de.srsoftware.oidc.datastore.file/build.gradle
  7. 51
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  8. 4
      de.srsoftware.oidc.web/src/main/resources/en/scripts/common.js
  9. 41
      de.srsoftware.oidc.web/src/main/resources/en/scripts/settings.js
  10. 25
      de.srsoftware.oidc.web/src/main/resources/en/settings.html

1
de.srsoftware.oidc.api/build.gradle

@ -13,6 +13,7 @@ dependencies { @@ -13,6 +13,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation 'org.json:json:20240303'
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
implementation 'com.sun.mail:jakarta.mail:2.0.1'
implementation project(':de.srsoftware.utils')
}

3
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Constants.java

@ -37,7 +37,8 @@ public class Constants { @@ -37,7 +37,8 @@ public class Constants {
public static final String RESPONSE_TYPE = "response_type";
public static final String SCOPE = "scope";
public static final String SECRET = "secret";
public static final String SENDER_ADDRESS = "sender_address";
public static final String SMTP_USER = "smtp_user";
public static final String SMTP_PASSWORD = "smtp_pass";
public static final String SMTP_AUTH = "smtp_auth";
public static final String SMTP_HOST = "smtp_host";
public static final String SMTP_PORT = "smtp_port";

8
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/MailConfig.java

@ -3,6 +3,7 @@ package de.srsoftware.oidc.api; @@ -3,6 +3,7 @@ package de.srsoftware.oidc.api;
import static de.srsoftware.oidc.api.Constants.*;
import jakarta.mail.Authenticator;
import java.util.Map;
import java.util.Properties;
@ -35,6 +36,7 @@ public interface MailConfig { @@ -35,6 +36,7 @@ public interface MailConfig {
props.put("mail.smtp.port", smtpPort());
props.put("mail.smtp.auth", smtpAuth() ? "true" : "false");
props.put("mail.smtp.starttls.enable", startTls() ? "true" : "false");
props.put("mail.smtp.ssl.trust", smtpHost());
return props;
}
@ -43,7 +45,11 @@ public interface MailConfig { @@ -43,7 +45,11 @@ public interface MailConfig {
SMTP_HOST, smtpHost(), //
SMTP_PORT, smtpPort(), //
SMTP_AUTH, smtpAuth(), //
SENDER_ADDRESS, senderAddress(), //
SMTP_USER, senderAddress(), //
START_TLS, startTls());
}
Authenticator authenticator();
MailConfig save();
}

26
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/EmailController.java

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.backend;
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.oidc.api.data.Permission.MANAGE_SMTP;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
@ -31,8 +32,33 @@ public class EmailController extends Controller { @@ -31,8 +32,33 @@ public class EmailController extends Controller {
return notFound(ex);
}
@Override
public boolean doPost(String path, HttpExchange ex) throws IOException {
var optSession = getSession(ex);
if (optSession.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED, ex);
var user = optSession.get().user();
switch (path) {
case "/settings":
return saveSettings(ex, user);
}
return notFound(ex);
}
private boolean provideSettings(HttpExchange ex, User user) throws IOException {
if (!user.hasPermission(MANAGE_SMTP)) return sendEmptyResponse(HTTP_FORBIDDEN, ex);
return sendContent(ex, mailConfig.map());
}
private boolean saveSettings(HttpExchange ex, User user) throws IOException {
if (!user.hasPermission(MANAGE_SMTP)) return sendEmptyResponse(HTTP_FORBIDDEN, ex);
var data = json(ex);
if (data.has(SMTP_HOST)) mailConfig.smtpHost(data.getString(SMTP_HOST));
if (data.has(SMTP_PORT)) mailConfig.smtpPort(data.getInt(SMTP_PORT));
if (data.has(SMTP_USER)) mailConfig.senderAddress(data.getString(SMTP_USER));
if (data.has(SMTP_PASSWORD)) mailConfig.senderPassword(data.getString(SMTP_PASSWORD));
if (data.has(SMTP_AUTH)) mailConfig.smtpAuth(data.getBoolean(SMTP_AUTH));
if (data.has(START_TLS)) mailConfig.startTls(data.getBoolean(START_TLS));
mailConfig.save();
return sendContent(ex, "saved");
}
}

9
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java

@ -22,18 +22,11 @@ import org.json.JSONObject; @@ -22,18 +22,11 @@ import org.json.JSONObject;
public class UserController extends Controller {
private final UserService users;
private final MailConfig mailConfig;
private final Authenticator auth;
public UserController(MailConfig mailConfig, SessionService sessionService, UserService userService) {
super(sessionService);
users = userService;
this.mailConfig = mailConfig;
auth = new Authenticator() {
// override the getPasswordAuthentication method
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(mailConfig.senderAddress(), mailConfig.senderPassword());
}
};
}
private boolean addUser(HttpExchange ex, Session session) throws IOException {
@ -127,7 +120,7 @@ public class UserController extends Controller { @@ -127,7 +120,7 @@ public class UserController extends Controller {
private void senPasswordLink(User user) {
LOG.log(WARNING, "Sending password link to {0}", user.email());
try {
var session = jakarta.mail.Session.getDefaultInstance(mailConfig.props(), auth);
var session = jakarta.mail.Session.getDefaultInstance(mailConfig.props(), mailConfig.authenticator());
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(mailConfig.senderAddress()));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(user.email()));

1
de.srsoftware.oidc.datastore.file/build.gradle

@ -16,6 +16,7 @@ dependencies { @@ -16,6 +16,7 @@ dependencies {
implementation project(':de.srsoftware.utils')
implementation 'org.json:json:20240303'
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
implementation 'com.sun.mail:jakarta.mail:2.0.1'
}

51
de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java

@ -9,6 +9,8 @@ import static java.util.Optional.empty; @@ -9,6 +9,8 @@ import static java.util.Optional.empty;
import de.srsoftware.oidc.api.*;
import de.srsoftware.oidc.api.data.*;
import jakarta.mail.Authenticator;
import jakarta.mail.PasswordAuthentication;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -37,6 +39,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -37,6 +39,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
private Map<String, Client> clients = new HashMap<>();
private Map<String, User> accessTokens = new HashMap<>();
private Map<String, Authorization> authCodes = new HashMap<>();
private Authenticator auth;
public FileStore(File storage, PasswordHasher<String> passwordHasher) throws IOException {
this.storageFile = storage.toPath();
@ -48,9 +51,10 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -48,9 +51,10 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
Files.writeString(storageFile, "{}");
}
json = new JSONObject(Files.readString(storageFile));
auth = null; // lazy init!
}
private FileStore save() {
public FileStore save() {
try {
Files.writeString(storageFile, json.toString(2));
return this;
@ -319,6 +323,19 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -319,6 +323,19 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
/*** MailConfig implementation ***/
@Override
public Authenticator authenticator() {
if (auth == null) {
auth = new Authenticator() {
// override the getPasswordAuthentication method
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(senderAddress(), senderPassword());
}
};
}
return auth;
}
private String mailConfig(String key) {
var config = json.getJSONObject(MAILCONFIG);
if (config.has(key)) return config.getString(key);
@ -328,71 +345,71 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -328,71 +345,71 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
private FileStore mailConfig(String key, Object newValue) {
var config = json.getJSONObject(MAILCONFIG);
config.put(key, newValue);
auth = null;
return this;
}
@Override
public String smtpHost() {
return mailConfig("smtp_host");
return mailConfig(SMTP_HOST);
}
@Override
public MailConfig smtpHost(String newValue) {
return mailConfig("smtp_host", newValue);
return mailConfig(SMTP_HOST, newValue);
}
@Override
public int smtpPort() {
try {
return Integer.parseInt(mailConfig("smtp_port"));
} catch (NumberFormatException nfe) {
return 0;
}
var config = json.getJSONObject(MAILCONFIG);
return config.has(SMTP_PORT) ? config.getInt(SMTP_PORT) : 0;
}
@Override
public MailConfig smtpPort(int newValue) {
return mailConfig("smtp_port", newValue);
return mailConfig(SMTP_PORT, newValue);
}
@Override
public String senderAddress() {
return mailConfig("sender_address");
return mailConfig(SMTP_USER);
}
@Override
public MailConfig senderAddress(String newValue) {
return mailConfig("sender_address", newValue);
return mailConfig(SMTP_USER, newValue);
}
@Override
public String senderPassword() {
return mailConfig("smtp_password");
return mailConfig(SMTP_PASSWORD);
}
@Override
public MailConfig senderPassword(String newValue) {
return mailConfig("smtp_password", newValue);
return mailConfig(SMTP_PASSWORD, newValue);
}
@Override
public boolean startTls() {
return "true".equals(mailConfig("start_tls"));
var config = json.getJSONObject(MAILCONFIG);
return config.has(START_TLS) ? config.getBoolean(START_TLS) : false;
}
@Override
public MailConfig startTls(boolean newValue) {
return mailConfig("start_tls", newValue);
return mailConfig(START_TLS, newValue);
}
@Override
public boolean smtpAuth() {
return "true".equals(mailConfig("smtp_auth"));
var config = json.getJSONObject(MAILCONFIG);
return config.has(SMTP_AUTH) ? config.getBoolean(SMTP_AUTH) : false;
}
@Override
public MailConfig smtpAuth(boolean newValue) {
return mailConfig("smtp_auth", newValue);
return mailConfig(SMTP_AUTH, newValue);
}
}

4
de.srsoftware.oidc.web/src/main/resources/en/scripts/common.js

@ -25,6 +25,10 @@ function hide(id){ @@ -25,6 +25,10 @@ function hide(id){
get(id).style.display = 'none';
}
function isChecked(id){
return get(id).checked;
}
function login(){
redirect('login.html?return_to='+encodeURIComponent(window.location.href));
}

41
de.srsoftware.oidc.web/src/main/resources/en/scripts/settings.js

@ -28,6 +28,24 @@ async function handlePasswordResponse(response){ @@ -28,6 +28,24 @@ async function handlePasswordResponse(response){
},10000);
}
async function handleSmtpResponse(response){
if (response.ok){
hide('wrong_password');
hide('password_mismatch');
setText('smtpBtn', 'saved.');
} else {
setText('smtpBtn', 'Update failed!');
var text = await response.text();
if (text == 'wrong password') show('wrong_password');
if (text == 'password mismatch') show('password_mismatch');
}
setTimeout(function(){
enable('smtpBtn');
setText('smtpBtn','Update');
},10000);
}
function handleResponse(response){
if (response.ok){
hide('update_error')
@ -36,8 +54,8 @@ function handleResponse(response){ @@ -36,8 +54,8 @@ function handleResponse(response){
show('update_error');
setText('updateBtn', 'Update failed!');
}
enable('updateBtn');
setTimeout(function(){
enable('updateBtn');
setText('updateBtn','Update');
},10000);
}
@ -49,6 +67,8 @@ async function handleSettings(response){ @@ -49,6 +67,8 @@ async function handleSettings(response){
for (var key in json){
setValue(key,json[key]);
}
get('start_tls').checked = json.start_tls;
get('smtp_auth').checked = json.smtp_auth;
show('mail_settings');
} else {
hide('mail_settings');
@ -59,6 +79,25 @@ function passKeyDown(ev){ @@ -59,6 +79,25 @@ function passKeyDown(ev){
if (event.keyCode == 13) updatePass();
}
function updateSmtp(){
disable('smtpBtn');
var newData = {
smtp_host : getValue('smtp_host'),
smtp_port : getValue('smtp_port'),
smtp_user : getValue('smtp_user'),
smtp_pass : getValue('smtp_pass'),
smtp_auth : isChecked('smtp_auth'),
start_tls : isChecked('start_tls')
}
fetch("/api/email/settings",{
method : 'POST',
headers : {
'Content-Type': 'application/json'
},
body : JSON.stringify(newData)
}).then(handleSmtpResponse);
setText('smtpBtn','sent…');
}
function updatePass(){

25
de.srsoftware.oidc.web/src/main/resources/en/settings.html

@ -78,6 +78,7 @@ @@ -78,6 +78,7 @@
</tr>
</table>
</fieldset>
<br/>
<fieldset id="mail_settings" style="display: none">
<legend>
Mail settings
@ -85,20 +86,32 @@ @@ -85,20 +86,32 @@
<table>
<tr>
<th>Smtp host</th>
<td><input type="text" id="smtp_host"></td>
<td><input type="text" id="smtp_host" placeholder="smtp host"></td>
</tr>
<tr>
<th>Smtp port</th>
<td><input type="text" id="smtp_port"></td>
<td><input type="number" id="smtp_port"></td>
</tr>
<tr>
<th>Sender email address</th>
<td><input type="text" id="sender_mail"></td>
<th>Smtp user</th>
<td><input type="text" id="smtp_user" placeholder="smtp user"></td>
</tr>
<tr>
<th>Sender password</th>
<td><input type="password" id="sender_password"></td>
<th>Smtp password</th>
<td><input type="password" id="smtp_pass" placeholder="password"></td>
</tr>
<tr>
<th>Security</th>
<td>
<label>
<input type="checkbox" id="smtp_auth"> Auth
</label>
<label>
<input type="checkbox" id="start_tls"> StartTLS
</label>
</td>
</tr>
<tr>
<td></td>
<td><button id="smtpBtn" type="button" onClick="updateSmtp()">Update</button></td>
</tr>

Loading…
Cancel
Save