Monthly Archives: July 2021

How To Use Spring Security With SAML Protocol Binding

In this post, I will show how we can use Spring Security with SAML Protocol Binding to integrate with Keycloak Identity Provider. And, if you want to read on how to use Keycloak, you can read here.

What is SAML?

SAML stands for Security Assertion Markup Language. It’s an open standard for
exchanging authentication and authorization data between a service provider (SP) and identity provider (IdP).

Identity Provider – performs authentication and validates user identity for authorization and passes that to Service Provider.

Service Provider – Trusts the identity provider and provides access to the user to service based on authorization.

SAML Authentication Flow

As part of this flow, we will be building a simple To-Do List Application. Henceforth, a user will access the application and he will be redirected for authentication.

SAML Authentication User Flow:

  1. User accesses Service Provider (SP) ToDo List Application.
  2. Application redirects user to Keycloak login screen. During this redirect, the application sends an AuthnRequest to Keycloak IDP.
  3. Keycloak IDP validates the request if it is coming from the right relying party/service provider. It checks for issuer and redirect URI (ACS URL).
  4. Keycloak IDP sends a SAML response back to Service Provider.
  5. Service Provider validates the signed response with provided IDP public certificate.
  6. If the response is valid, we will extract the attribute NameID from the assertion and logged the user in.

 

How to use Spring Security with SAML Protocol

NoteSpring Security SAML extension was a library that used to provide SAML support.
But after 2018, Spring Security team moved that project and now supports SAML
2 authentication as part of core Spring Security.

Use Spring Security with SAML Protocol Binding

Therefore, once you create a Spring Boot project, we will need to import the following dependencies.


dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	/*
	 * Spring Security
	 */
	implementation 'org.springframework.boot:spring-boot-starter-security'
	runtimeOnly 'mysql:mysql-connector-java'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	implementation 'org.springframework.security:spring-security-saml2-service-provider:5.3.5' +
			'.RELEASE'

	/*
	 * Keycloak
	 */
	implementation 'org.keycloak:keycloak-spring-boot-starter:11.0.3'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

Accordingly, the dependency spring-security-saml2-service-provider will allow us to add relying party registration. It also helps with identity provider registration.

Now, we will add this registration in ourSecurityConfig as below:


    @Bean
    public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() throws CertificateException
    {
        final String idpEntityId = "http://localhost:8180/auth/realms/ToDoListSAMLApp";
        final String webSSOEndpoint = "http://localhost:8180/auth/realms/ToDoListSAMLApp/protocol/saml";
        final String registrationId = "keycloak";
        final String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata" +
                "/{registrationId}";
        final String acsUrlTemplate = "{baseUrl}/login/saml2/sso/{registrationId}";


        Saml2X509Credential idpVerificationCertificate;
        try (InputStream pub = new ClassPathResource("credentials/idp.cer").getInputStream())
        {
            X509Certificate c = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(pub);
            idpVerificationCertificate = new Saml2X509Credential(c, VERIFICATION);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }

        RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration
                .withRegistrationId(registrationId)
                .providerDetails(config -> config.entityId(idpEntityId))
                .providerDetails(config -> config.webSsoUrl(webSSOEndpoint))
                .providerDetails(config -> config.signAuthNRequest(false))
                .credentials(c -> c.add(idpVerificationCertificate))
                .assertionConsumerServiceUrlTemplate(acsUrlTemplate)
                .build();

        return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
    }

Our login will also change with HttpSecurity as follows:

httpSecurity.authorizeRequests()
.antMatchers("/js/**","/css/**","/img/**").permitAll()
.antMatchers("/signup","/forgotpassword").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.saml2Login(Customizer.withDefaults()).exceptionHandling(exception ->
exception.authenticationEntryPoint(entryPoint()))
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.deleteCookies("JSESSIONID")
.permitAll();

We are now using saml2Login . By default, if you access the application, it will redirect to an identity provider. We want to configure our custom login page before it can be redirected to the identity provider – keycloak. That’s why we have authenticationEntryPoint which allows us to configure our custom login page. So now if we access our application at https://localhost:8743/login, we will see the below login page:

So once you select the option for Login with Keycloak SAML, it will send a AuthnRequest to Keycloak. Also, this request is an unsigned request. Keycloak will send a signed response. A controller will receive this signed response to decode NameId attribute.


@GetMapping(value="/index")
public String getHomePage(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal saml2AuthenticatedPrincipal)
{
   String principal = saml2AuthenticatedPrincipal.getName();
   model.addAttribute("username", principal);
   return "index";
}

Once the NameId is retrieved, it will log the user in.

Configuration on Keycloak

We will have to configure our application in the Keycloak administration console.

  • Create a REALM for your application.
  • Select Endpoints – SAML 2.0 IdP Metadata
  • In Clients – Add the service provider.
  • For your client, configure Root URL, SAML Processing URL (https://localhost:8743/saml2/service-provider-metadata/keycloak)
  • You can also adjust the other settings like – signing assertions, including AuthnStatement.
  • Certainly, configure the ACS URL in “Fine Grain SAML Endpoint Configuration” section.

Code Repository

The code for this project is available in my github repository. I also covered this in more detail in my book Simplifying Spring Security. To learn more, you can buy my book here.

Conclusion

In this post, I showed how to use Spring Security with SAML Protocol. Over the years, there have been a lot of improvements in Spring Security and now it can easily be used with different protocols like OAuth, OIDC. If you enjoyed this post, subscribe to my blog here.

Using Apache Kafka With Spring Boot

In this post, I will show how we can integrate Apache Kafka with a Spring Boot application. I will also show how we can send and consume messages from our application.

What is Apache Kafka?

I previously wrote an introductory post about kafka. But if you still don’t know anything about Kafka, then this will be a good summary.

Kafka is a stream processing platform, currently available as open-source software from Apache. Kafka provides low latency ingestion of large amounts of data.

Nevertheless, one key advantage of Kafka is it allows to move large amounts of data and process it in real-time. Kafka takes into account horizontal scaling, which means it can be scaled by increasing more brokers in Kafka cluster.

Kafka Terminology

So, Kafka has its own terminology. But, it is also easy to understand if you are starting up.

  1. Producer – A Producer is a client that produces a message and sends it to Kafka Server on a specified topic.
  2. Consumer – A Consumer is a client that consumes the message from Kafka topic.
  3. Cluster – Kafka is a distributed system of brokers. Multiple brokers make a cluster.
  4. Broker – Kafka broker can create a Kafka cluster by sharing information between each other directly or indirectly through zookeeper. Therefore, a broker receives a message from the producer and the consumer fetches this message from the broker by topic, partition and offset.
  5. Topic – A topic is a category name to which the producer sends messages to and consumer consumes the messages from.
  6. Partition – Messages to a topic are spread across kafka clusters into several partitions.
  7. Offset – Offset is a pointer to the last message that Kafka has sent to the consumer.

Setting Up Spring Boot Application

As part of this post, I will show how we can use Apache Kafka with a Spring Boot application.

We will run a Kafka Server on the machine and our application will send a message through the producer to a topic. Part of the application will consume this message through the consumer.

To start with, we will need a Kafka dependency in our project.


implementation 'org.springframework.kafka:spring-kafka:2.5.2'

We will have a REST controller which will basically take a JSON message and send it to Kafka topic using Kafka Producer.


package com.betterjavacode.kafkademo.resource;

import com.betterjavacode.kafkademo.model.Company;
import com.betterjavacode.kafkademo.producers.KafkaProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "/v1/kafka")
public class KafkaRestController
{
    private final KafkaProducer kafkaProducer;

    @Autowired
    public KafkaRestController(KafkaProducer kafkaProducer)
    {
        this.kafkaProducer = kafkaProducer;
    }

    @PostMapping(value = "/send", consumes={"application/json"}, produces = {"application/json"})
    public void sendMessageToKafkaTopic(@RequestBody Company company)
    {
        this.kafkaProducer.sendMessage(company);
    }
}

This KafkaProducer uses KafkaTemplate to send the message to a topic. KafkaProducer is a service that we created for this application.


@Service
public class KafkaProducer
{
    private static final Logger logger = LoggerFactory.getLogger(KafkaProducer.class);
    private static final String topic = "companies";

    @Autowired
    private KafkaTemplate<String, Company> kafkaTemplate;

    public void sendMessage(Company company)
    {
        logger.info(String.format("Outgoing Message - Producing -> %s", company));
        this.kafkaTemplate.send(topic, company);
    }
}

Similarly, we will have our consumer.


@Service
public class KafkaConsumer
{
    private final Logger logger = LoggerFactory.getLogger(KafkaConsumer.class);

    @KafkaListener(topics = "companies", groupId = "group_id")
    public void consume(String company)
    {
        logger.info(String.format("Incoming Message - Consuming -> %s", company));
    }
}

Our consumer is using KafkaListener which allows us to listen to a topic. When a message comes to this topic, the listener alerts the consumer and the consumer picks up that message.

Kafka Configuration

Before, showing how we will send and consume these messages, we still need to configure kafka cluster in our application. There are also some other properties our producer and consumer will need.

Basically, there are two ways to configure these properties. Either programmatically OR through YML configuration. For our application, I have configured this through yaml configuration file.


server:
  port: 9000
spring:
  kafka:
    consumer:
      bootstrap-servers: localhost:9092
      group-id: group_id
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      properties:
        spring.json.trusted.packages: "com.betterjavacode.kafkademo.model"
    producer:
      bootstrap-servers: localhost:9092
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer

bootstrap-servers – Host and Port on which Kafka Server is running
key-deserializer – class to use to deserialize the key of the message that the consumer consumes
value-deserializer – class to use to deserialize the value of the message that the consumer consumes
key-serializer – Serializer class to serialize the key of the message that the producer produces
value-serializer – Serializer class to serialize the value of the message
group-id – This specifies the group to which the consumer belongs to

auto-offset-reset – Each message in a partition of a Kafka topic has a unique identifier which is the offset. This setting automatically resets the offset to the earliest.

Before we can send messages, our topic must exist. I will manually create this topic and show in the next section. In the Spring Boot application, we can create a KafkaAdmin bean and use it to create topics as well.

Running Kafka Server

As part of this demo, I will also show how we can start our first instance of Kafka server. Download the Kafka from here.

Once you download and extract in a directory, we will have to edit two properties in zookeeper.properties and server.properties.

Update zookeeper.properties with data directory (dataDir) where you want a zookeeper to store data.

Start the zookeeper – zookeeper-server-start.bat ../../config/zookeeper.properties

Update server.properties with logs directory.

Start the server – kafka-server-start.bat ../../config/server.properties

Now to create a topic, we can run another command prompt and use this command
kafka-topics.bat –create –topic companies–bootstrap-server localhost:9092  from the directory where we installed kafka.

Sending and Consuming Messages

So far, we have created a Spring Boot application with Kafka. We have configured our Kafka server. Now comes the moment to send and consume messages to Kafka topic.

We have a REST API to send a message about a company. This message then Kafka Producer will send it to Kafka Topic companies. A Kafka consumer will read this message from the topic as it will be listening to it.

Once this message is sent, we can take a look at our application server log as it will show about producing this message through Kafka Producer.

At the same time, our Consumer is listening. So, it will pick up this message to consume.

 

Conclusion

So far, we have shown how we can use Apache Kafka with the Spring Boot application. With data in applications is increasing, it becomes important to stream with low latency. The code repository for this demo application is here.

If you want me to cover anything else with Kafka, feel free to comment on this post and I will cover more details about Kafka in upcoming posts.

What Makes a Good Junior Developer

What makes a good Junior Developer? Yes, I will talk about some qualities every junior developer should develop to do better in this role. Now Junior Developer is a broad term, it can include Associate Software Engineers, Software Engineers, or Developers.

Once I was a Junior Developer too. Now I am in a senior role, but that doesn’t take away from me to still be a junior to other Seniors. So, I wish there was some kind of a guide to help junior developers to succeed in their roles.

Qualities that will help you succeed as a Junior Developer

  1. Be open-minded to take up a challenge – One quality I really appreciate about the junior developers that I have worked with so far is to take up a challenge. In the initial days, you want to learn as much as you can. Sometimes, it can be overwhelming, other times, it can be boring. But learn and read.
  2. Take ownership of the task you work on – If you get a task to work on, take ownership of that task till its completion. You can create trust with your peers by taking ownership of the task. If you get stuck with the task, ask questions about it to your seniors. Senior Developers are meant to help you.
  3. Ask questions – As a senior developer, I really appreciate developers who ask questions. Even if those questions can be easy to answer. If you are stuck or don’t know, ask the question. Even in meetings, if you ask a question, everybody should appreciate it. A question brings a different perspective. And every perspective matters.
  4. Help others – One way to build your career at any organization is by helping others as much as you can. So, help others. You solved a problem that many other developers are facing, share that knowledge. If you built an automation tool, share the tool. Other junior developers come to you, help them. Be so good that everyone comes to you.

How to understand the system as a Junior Developer

Everyone has their own way to learn any skill or a complex system. But there are a few tried and tested ideas that can help you understand the system. This is definitely helpful in your initial days at any organization as a junior developer.

  1. Read and take notes. If there is documentation for the system architecture, read as much as you can. This will help you get the bigger picture of the system. If there is no documentation, then you are up against a challenge. Try to identify the components of the system that communicate with each other. Start creating documentation yourself so the future junior developers can thank you.
  2. Take up a task. Once you get a bigger picture, take up a task and work on it. Do a microanalysis of part of the system that you work on. Now this will provide you both a short distance view as well as a long-distance view of your system. Also, remember understanding any complex system takes time, so don’t be discouraged if you do not understand everything in a month or two.
  3. Read about system design in general. One way to build up your knowledge about any complex system is by reading about system design. Another way is to read the engineering blog of your company. A lot of passionate developers write these engineering blogs to share their knowledge worldwide.

Tips to succeed as a Junior Developer

  1. Read code – Read the code of the system you are working on. This will make you comfortable with code as well. Create your questions based on reading the code that you can ask senior developers.
  2. Participate in Code Review – One thing you will learn from code review to see how senior developers help in improving the code quality, so you can adapt to that quality. You will also learn to review others’ code.
  3. Write unit test cases – For whatever code you write, write unit test cases. This will set you apart from other developers.
  4. Start understanding where your team is struggling – Become a person who can identify a problem and find a solution. It’s very rare to find high-agency developers, but you can build up that skill. See where your team is struggling and how you can help the team in not struggling. Every team struggles with something. If as a Junior Developer, you have time, then help your team by building a tool or creating documentation of the system that has been ignored.
  5. Do not compare – Do not compare yourself with fellow junior or senior developers. Everyone’s path is different. So focus on what you can and can not do. Improve your skills.
  6. Ask for feedback – If there is no way to get feedback from a manager or senior developers, check in with your seniors once a month to get feedback. Feedback helps to improve. Find your own weaknesses and work on them.

Conclusion

In this post, I shared some tips and skills that a Junior Developer can use to be successful. If you enjoyed this post, comment on this post telling me what skill you think can make a Junior Developer stand out.

If you are still looking for my book Simplifying Spring Security, it is here to buy.