Skip to content

Commit

Permalink
Merge pull request #3208 from Kehrlann/dgarnier/javaconfig
Browse files Browse the repository at this point in the history
Move `login-ui` Service classes to Javaconfig
  • Loading branch information
strehle authored Jan 8, 2025
2 parents 922f0c7 + 30e5505 commit 142604b
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
package org.cloudfoundry.identity.uaa.account;

import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.cloudfoundry.identity.uaa.message.MessageService;
import org.cloudfoundry.identity.uaa.message.MessageType;
import org.cloudfoundry.identity.uaa.oauth.provider.ClientDetails;
import org.cloudfoundry.identity.uaa.provider.NoSuchClientException;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceAlreadyExistsException;
import org.cloudfoundry.identity.uaa.scim.util.ScimUtils;
import org.cloudfoundry.identity.uaa.scim.validate.PasswordValidator;
import org.cloudfoundry.identity.uaa.util.JsonUtils;
import org.cloudfoundry.identity.uaa.provider.NoSuchClientException;
import org.cloudfoundry.identity.uaa.zone.MultitenantClientServices;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.MergedZoneBrandingInformation;
import org.cloudfoundry.identity.uaa.zone.MultitenantClientServices;
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.cloudfoundry.identity.uaa.oauth.provider.ClientDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;

import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.cloudfoundry.identity.uaa.codestore.ExpiringCodeType.REGISTRATION;
import static org.cloudfoundry.identity.uaa.util.UaaUrlUtils.findMatchingRedirectUri;
import static org.springframework.http.HttpStatus.BAD_REQUEST;

@Service
public class EmailAccountCreationService implements AccountCreationService {

private final Logger logger = LoggerFactory.getLogger(getClass());
Expand All @@ -48,7 +55,7 @@ public class EmailAccountCreationService implements AccountCreationService {
private final IdentityZoneManager identityZoneManager;

public EmailAccountCreationService(
SpringTemplateEngine templateEngine,
@Qualifier("mailTemplateEngine") SpringTemplateEngine templateEngine,
MessageService messageService,
ExpiringCodeStore codeStore,
ScimUserProvisioning scimUserProvisioning,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,32 @@
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.cloudfoundry.identity.uaa.message.MessageService;
import org.cloudfoundry.identity.uaa.message.MessageType;
import org.cloudfoundry.identity.uaa.oauth.provider.ClientDetails;
import org.cloudfoundry.identity.uaa.provider.NoSuchClientException;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
import org.cloudfoundry.identity.uaa.util.JsonUtils;
import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
import org.cloudfoundry.identity.uaa.provider.NoSuchClientException;
import org.cloudfoundry.identity.uaa.zone.MergedZoneBrandingInformation;
import org.cloudfoundry.identity.uaa.zone.MultitenantClientServices;
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager;
import org.cloudfoundry.identity.uaa.oauth.provider.ClientDetails;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.sql.Timestamp;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.cloudfoundry.identity.uaa.codestore.ExpiringCodeType.EMAIL;
import static org.cloudfoundry.identity.uaa.util.UaaUrlUtils.findMatchingRedirectUri;

@Service
public class EmailChangeEmailService implements ChangeEmailService {

static final String CHANGE_EMAIL_REDIRECT_URL = "change_email_redirect_url";
Expand All @@ -38,7 +45,8 @@ public class EmailChangeEmailService implements ChangeEmailService {
private final MultitenantClientServices clientDetailsService;
private final IdentityZoneManager identityZoneManager;

EmailChangeEmailService(final TemplateEngine templateEngine,
EmailChangeEmailService(
@Qualifier("mailTemplateEngine") final TemplateEngine templateEngine,
final MessageService messageService,
final ScimUserProvisioning scimUserProvisioning,
final ExpiringCodeStore codeStore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

import static org.cloudfoundry.identity.uaa.constants.OriginKeys.UAA;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;

@Service
public class UaaChangePasswordService implements ChangePasswordService, ApplicationEventPublisherAware {

private final ScimUserProvisioning scimUserProvisioning;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.cloudfoundry.identity.uaa.oauth.provider.ClientDetails;

import java.sql.Timestamp;
Expand All @@ -39,6 +40,7 @@
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import static org.springframework.util.StringUtils.isEmpty;

@Service("resetPasswordService")
public class UaaResetPasswordService implements ResetPasswordService, ApplicationEventPublisherAware {

public static final int PASSWORD_RESET_LIFETIME = 30 * 60 * 1000;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,138 @@
package org.cloudfoundry.identity.uaa.impl.config;

import org.cloudfoundry.identity.uaa.message.EmailService;
import org.cloudfoundry.identity.uaa.message.LocalUaaRestTemplate;
import org.cloudfoundry.identity.uaa.message.MessageService;
import org.cloudfoundry.identity.uaa.message.MessageType;
import org.cloudfoundry.identity.uaa.message.NotificationsService;
import org.cloudfoundry.identity.uaa.message.util.FakeJavaMailSender;
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* Configuration for sending e-mails or HTTP-based notifications, e.g. on account creation.
* <p>
* If a {@code notifications.url} property is defined, it uses HTTP-based notifications.
* Otherwise, if {@code smtp.*} properties are defined, it will send e-mails. If none of
* these properties are configured, it uses a {@link FakeJavaMailSender} mailer.
* <p>
* All beans are marked lazy except {@link NotificationConfiguration#notificationMessageService},
* as they are all "fallback" options and do not need to be created when {@code notifications.url}
* is defined.
*/
@Lazy
@Configuration
@EnableConfigurationProperties(SmtpProperties.class)
public class LoginServerConfig {

/**
* Fallback bean for when there is no "notifications.url".
* TODO: dgarnier annotate with @Fallback in Boot 3.4
*
* @return -
*/
@Bean
public MessageService messageService(EmailService emailService, NotificationsService notificationsService, Environment environment) {
if (environment.getProperty("notifications.url") != null && !"".equals(environment.getProperty("notifications.url"))) {
return notificationsService;
} else {
return emailService;
public MessageService emailMessageService(
// dgarnier: use DEFAULT_UAA_URL
@Value("${login.url:http://localhost:8080/uaa}") String loginUrl,
JavaMailSender mailSender,
SmtpProperties smtpProperties,
IdentityZoneManager identityZoneManager) {
return new EmailService(
mailSender,
loginUrl,
smtpProperties.fromAddress(),
identityZoneManager
);
}

/**
* Fallback for SMTP mail sender, when no real mail sender is used. This is mostly used in tests.
* TODO: dgarnier annotate with @Fallback in Boot 3.4
*
* @return -
*/
@Bean
JavaMailSender fakeJavaMailSender() {
return new FakeJavaMailSender();
}

@Bean
@Primary
@ConditionalOnProperty(value = "smtp.host", matchIfMissing = false)
JavaMailSender smtpMailSender(SmtpProperties smtpProperties) {
var mailSender = new JavaMailSenderImpl();
mailSender.setHost(smtpProperties.host());
mailSender.setPort(smtpProperties.port());
mailSender.setPassword(smtpProperties.password());
mailSender.setUsername(smtpProperties.user());

var javaMailProperties = new Properties();
javaMailProperties.put("mail.smtp.auth", smtpProperties.auth());
javaMailProperties.put("mail.smtp.starttls.enable", smtpProperties.starttls());
javaMailProperties.put("mail.smtp.ssl.protocols", smtpProperties.sslprotocols());
mailSender.setJavaMailProperties(javaMailProperties);
return mailSender;
}

@Configuration
@ConditionalOnProperty(value = "notifications.url", matchIfMissing = false)
@EnableConfigurationProperties(NotificationsProperties.class)
static class NotificationConfiguration {

/**
* HTTP-based {@link MessageService}. Takes precedence over any email-basedO
* configuration.
*
* @param notificationsTemplate -
* @param notificationsProperties -
* @return -
*/
@Bean
@Primary
public MessageService notificationMessageService(
LocalUaaRestTemplate notificationsTemplate,
NotificationsProperties notificationsProperties
) {
return new NotificationsService(
notificationsTemplate,
notificationsProperties.url(),
notifications(),
notificationsProperties.sendInDefaultZone()
);
}

private static Map<MessageType, HashMap<String, Object>> notifications() {
return Map.of(
MessageType.CREATE_ACCOUNT_CONFIRMATION, notification("Send activation code", "f7a85fdc-d920-41f0-b3a4-55db08e408ce"),
MessageType.PASSWORD_RESET, notification("Reset Password", "141200f6-93bd-4761-a721-941ab511ba2c"),
MessageType.CHANGE_EMAIL, notification("Change Email", "712de257-a7fa-44cb-b1ac-8a6588d1be23"),
MessageType.INVITATION, notification("Invitation", "e6722687-3f0f-4e7a-9925-839a04712cea")
);
}

private static HashMap<String, Object> notification(String description, String id) {
return new HashMap<>(
Map.of(
"description", description,
"id", id,
"critical", true
)
);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.cloudfoundry.identity.uaa.impl.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConfigurationProperties(prefix = "notifications")
record NotificationsProperties(
String url,
@DefaultValue("true") boolean sendInDefaultZone
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cloudfoundry.identity.uaa.impl.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConfigurationProperties(prefix = "smtp")
public record SmtpProperties(
@DefaultValue("localhost") String host,
@DefaultValue("25") int port,
@DefaultValue("") String user,
@DefaultValue("") String password,
@DefaultValue("false") boolean auth,
@DefaultValue("false") boolean starttls,
@DefaultValue("TLSv1.2") String sslprotocols,
@DefaultValue("") String fromAddress
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class ForcePasswordChangeController {

public ForcePasswordChangeController(
final ResourcePropertySource resourcePropertySource,
final @Qualifier("resetPasswordService") ResetPasswordService resetPasswordService) {
ResetPasswordService resetPasswordService) {
this.resourcePropertySource = resourcePropertySource;
this.resetPasswordService = resetPasswordService;
}
Expand Down
Loading

0 comments on commit 142604b

Please sign in to comment.