Tag Archives: Spring

Using Gmail as SMTP server from Java, Spring Boot apps

Gmail users can use Gmail’s SMTP server smtp.gmail.com to send emails from their Spring Boot apps. For this let us do some setup in the app:

  1. Provide SMTP connection properties in the application.properties file:
    spring.mail.host=smtp.gmail.com
    spring.mail.username=<your gmail/google app email>
    spring.mail.password=*****
    spring.mail.port=587
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.auth=true
    spring.mail.properties.mail.smtp.starttls.required=true
  2. Use Spring Boot Email tools library – which is a wrapper over Spring Boot Email starter library.  Add the following in your pom.xml:
    <dependency>
        <groupId>it.ozimov</groupId>
        <artifactId>spring-boot-email-core</artifactId>
        <version>0.6.3</version>
    </dependency>
  3. Annotation your application’s main class (i.e class annotated with @SpringBootApplication) with @EnableEmailTools:
    @SpringBootApplication
    @EnableEmailTools
    public class EmailApplication {
        public static void main(String[] args){
            SpringApplication.run(EmailApplication.class, args);
        }
    }
  4. Let’s write a test which uses it.ozimov.springboot.mail.service.EmailService bean to send an email:
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class EmailServiceTest {
        @Autowired 
        it.ozimov.springboot.mail.service.EmailService emailService; 
    
        @Value("${spring.mail.username}") String fromEmail; 
        @Test 
        public void testSendEmail() throws UnsupportedEncodingException { 
            User user = new User(); 
            user.setEmail("sanaulla123@gmail.com"); 
            user.setDisplayName("Mohamed Sanaulla"); 
            final Email email = DefaultEmail.builder() 
                .from(new InternetAddress(fromEmail, "From Name"))
                .to(Lists.newArrayList(new InternetAddress(
                    user.getEmail(), user.getDisplayName()))) 
                .subject("Testing email")
                .body("Testing body ...")
                .encoding("UTF-8").build();
            emailService.send(email); 
        }
    }

Continue reading

Advertisements

Gotcha: Migrating from Spring Security 3.2.x to Spring Security 4.x

Here is a simple gotcha to keep in mind while migrating to newer Spring Security version 4.x from Spring Security 3.2.x

What’s the problem?

The Spring security configuration expressions hasRole('role_name') and hasAuthority('role_name') are no longer the same.

The catch is: hasAuthority checks for any role name passed to the expression without prepending ‘ROLE_’ (which is the default role prefix), where as hasRole checks for any role name passed to the expression by prepending ‘ROLE_’ to the role name.

Below is the snapshot of the class definition for SecurityExpressionRoot for both the versions of Spring Security which defines the methods hasRole and hasAuthority.

springsec-gotcha

In Spring Security 3.2.x hasAuthority and hasRole are checking for the presence of given role name in getAuthoritySet() [The getAuthoritySet() retrieves the GrantedAuthority list for the user]

In Spring Security 4.x hasAuthority is invoking the API hasAnyAuthorityName passing the prefix as null whereas hasRole is invoking the API hasAnyAuthorityName passing the default prefix which is ‘ROLE_’ (the same has been highlighted in the image above)

There is another interesting API in Spring Security 4.x (again highlighted in the image above) called getRoleWithDefaultPrefix() as shown in image below:

springsec4-2.png

Interesting to see above how the role name is being prefixed with the role prefix.

What is the fix?

  1. Either you append all your roles with ‘ROLE_’ prefix. OR
  2. Use hasAuthority as the replacement for hasRole expression without the need for changing the role names OR
  3. Override the defaultRolePrefix with null or empty string so that the same expression hasRole works with the same role names. [I need to figure out how to do this. It should be possible because the setter for the property is public]