Browsed by
Month: August 2020

Spring Security 5 OIDC login with Onelogin

Spring Security 5 OIDC login with Onelogin

I recently did an integration with Spring Security 5 and Spring Boot 2 using onelogin as the OIDC provider. I was having many issues getting Spring Oauth to just work, so here are some notes about how I made it work in onelogin. In particular, I had many issues, after going through the whole flow, while calling the token endpoint to finally get an auth token. Which ends up being pretty well all the way to the end of the regular flow.

The error I was getting was:

Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized

The first thing you will need is the following dependencies on your classpath:

implementation("org.springframework.boot:spring-boot-starter-security")
implementation ("org.springframework.security:spring-security-oauth2-client:5.3.4.RELEASE")
implementation ("org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE")
implementation("org.springframework.boot:spring-boot-starter-web")

Next, you need to make sure you have all (3!) of your application.yml attributes to allow spring boot to autoconfig your client. IT should look about like this:

spring:
  application:
    name: demo-oauth-oidc
  thymeleaf:
    cache: false
  security:
    oauth2:
      client:
        provider:
          onelogin:
            issuer-uri: https://<my domain>.onelogin.com/oidc/2
        registration:
          onelogin:
            client-id: <onelogin client id>
            client-secret: <onelogin secret>

Note above, under provider and registration, I used the same word, onelogin. This ends up being how you can refer to that particular auth mechanism in many places in the code, as well as the associated URLs in the system for that scheme. If you want to use multiple auth schemes, you can simply add additional new entities under provider and registration sections with unique names.

Once you have those dependencies, you need to configure onelogin from within the onelogin tile configuration system to allow spring to interact. The following settings need to be set:

  • Set your login URL in onelogin Configuration
    • <myUrl>/oauth2/authorization/onelogin
  • Set your redirect URLs in onelogin Configuration
    • <myUrl>/login/oauth2/code/onelogin
  • In the onelogin SSO section, set application type = web
  • In the onelogin SSO section, set Token Endpoint Authentication method to Basic

Once you have all these things in place, you should be able to ./gradlew bootRun your app and navigate to <myurl>/login to initiate the onelogin oauth SSO OICD process!

Spring java file and data upload

Spring java file and data upload

If you need to make a service endpoint in spring that takes a file and some structured data, like json, you might find that spring is less than happy about that working in the normal way you might be used to.

In order to make this work, you want the endpoint to take a multipartFile object and a string object. Using a domain object and hoping spring marshals it will not work. Below is an example of how to do this in Spring 5.

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

  @PostMapping("/dataAndFile")
  public ResponseEntity dataAndFileUpload(
      @RequestPart(value = "dataInput") String dataInput,
      @RequestPart(value = "csv") MultipartFile csv
  ) throws IOException {

    ObjectMapper bulkObject = new ObjectMapper();
    HashMap input = bulkObject.readValue(dataInput, HashMap.class);
    InputStream thefile = csv.getInputStream();

    return new ResponseEntity(HttpStatus.OK);
  }