## Spring Boot Authentication with FreeIPA

April 24 2018 by [Chris](/content/chris@techdevsolutions.com)

[FreeIPA](https://www.freeipa.org/) is a free LDAP authentication system. Today we will integrate it with Spring Boot.

This guide assumes you have a knowledge of and working instance of a secured Spring Boot application. You can find a guide [here](https://spring.io/guides/gs/spring-boot/). Click [here](https://spring.io/guides/gs/securing-web/) for how to secure a Spring Boot application. We will assume you have a secured Spring Boot application for this point forward.

In your SpringWebSecurityConfig file (or whatever you called your class that extended WebSecurityConfigurerAdapter), add the following override:

```
 ...
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.authenticationProvider(freeIpaAuthenticationManager);
}
...
```

Add the following to your application.yaml:

```
freeipa.base.url: https://ipa.demo1.freeipa.org
```

Finally, we implement the freeIpaAuthenticationManager method:

```
 @Component
public class FreeIpaAuthenticationManager implements AuthenticationProvider {
    private Logger logger = Logger.getLogger(FreeIpaAuthenticationManager.class.getName());
    private final String LOGIN_SERVICE = "/ipa/session/login_password";
    private final String LOOKUP_SERVICE = "/ipa/session/json";
    private final String LOOKUP_REFERER = "/ipa/ui/";

private Environment environment;
    private String baseUrl = "";

@Autowired
    public FreeIpaAuthenticationManager(Environment environment) {
        this.environment = environment;
    }

@Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        this.baseUrl = this.environment.getProperty("freeipa.base.url");

String username = authentication.getName();
        String password = authentication.getCredentials().toString();

Map<String, Object> lookup = this.auth(username, password);
        Boolean authenticated = (Boolean) lookup.get("authenticated");
        Map<String, Object> principal = (Map<String, Object>) lookup.get("principal");
        List<GrantedAuthority> roles = (List<GrantedAuthority>) lookup.get("authorities");

if (authenticated) {
            return new UsernamePasswordAuthenticationToken(principal, password, roles);
        } else {
            throw new BadCredentialsException("FreeIpaAuthenticationManager - Authentication failed for: " + username);
        }
    }

@Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

private Map<String, Object> auth(String username, String password) {
        Map<String, Object> lookup = new HashMap<>();
        lookup.put("authenticated", false);
        lookup.put("principal", new HashMap<String, Object>());
        lookup.put("authorities", new ArrayList<GrantedAuthority>());

try {
            CloseableHttpClient client = HttpClients.custom().
                    setHostnameVerifier(new AllowAllHostnameVerifier()).
                    setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                        public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                            return true;
                        }
                    }).build()).build();
            this.logger.info("FreeIpaAuthenticationManager - auth - URL: " + this.baseUrl + LOGIN_SERVICE);
            HttpPost httpPost = new HttpPost(this.baseUrl + LOGIN_SERVICE);

List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("user", username));
            params.add(new BasicNameValuePair("password", password));
            httpPost.setEntity(new UrlEncodedFormEntity(params));

CloseableHttpResponse response = client.execute(httpPost);
            Integer statusCode = response.getStatusLine().getStatusCode();

if (statusCode == 200) {
                String cookie = "";

for (Header header : response.getAllHeaders()) {
                    if (header.getName().equals("Set-Cookie")) {
                        cookie = header.getValue();
                    }
                }

if (StringUtils.isNotEmpty(cookie)) {
                    lookup = this.lookup(client, cookie, username, lookup);
                } else {
                    this.logger.info("FreeIpaAuthenticationManager - auth - error - cookie is empty");
                }
            } else if(statusCode == 401) {
                this.logger.info("FreeIpaAuthenticationManager - auth - Unauthorized");
            } else {
                this.logger.info("FreeIpaAuthenticationManager - auth - error - statusCode: " + statusCode);
            }

client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

return lookup;
    }

private Map<String, Object> lookup(CloseableHttpClient client, String cookie, String username, Map<String, Object> lookup) throws IOException {
        HttpPost httpPost = new HttpPost(this.baseUrl + LOOKUP_SERVICE);
        httpPost.setHeader("Cookie", cookie);
        httpPost.setHeader("Referer",this.baseUrl +  LOOKUP_REFERER);
        httpPost.setHeader("Content-Type", "application/json");
        HttpEntity entity = new NStringEntity("{\"method\":\"user_show/1\",\"params\":[[\"" + username + "\"],{\"all\":true,\"version\":\"2.229\"}]}", ContentType.APPLICATION_JSON);
        httpPost.setEntity(entity);
        CloseableHttpResponse response = client.execute(httpPost);
        Integer statusCode = response.getStatusLine().getStatusCode();

if (statusCode == 200) {
            String responseBody = EntityUtils.toString(response.getEntity());
            Map<String, Object> map = new ObjectMapper().readValue(responseBody, Map.class);

if (map != null) {
                Map<String, Object> principal = (Map<String, Object>) map.get("result");

if (principal != null) {
                    Map<String, Object> principalDetails = (Map<String, Object>) principal.get("result");

if (principalDetails != null) {
                        List<String> groups = (List<String>) principalDetails.get("memberof_group");

if (groups != null) {
                            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

for (String group : groups) {
                                GrantedAuthority authority = new SimpleGrantedAuthority(group);
                                authorities.add(authority);
                            }

lookup.put("authenticated", true);
                            lookup.put("principal", principal);
                            lookup.put("authorities", authorities);
                            this.logger.info("FreeIpaAuthenticationManager - authenticated: " + username + ", authorities: " + authorities);
                        } else {
                            this.logger.info("FreeIpaAuthenticationManager - lookup - error - Unexpected response (groups)");
                        }
                    } else {
                        this.logger.info("FreeIpaAuthenticationManager - lookup - error - Unexpected response (principalDetails)");
                    }
                } else {
                    this.logger.info("FreeIpaAuthenticationManager - lookup - error - Unexpected response (principal)");
                }
            } else {
                this.logger.info("FreeIpaAuthenticationManager - lookup - error - Unexpected response (map)");
            }
        } else if (statusCode == 401) {
            this.logger.info("FreeIpaAuthenticationManager - lookup - Unauthorized");
        } else {
            this.logger.info("FreeIpaAuthenticationManager - lookup - error - statusCode: " + statusCode);
        }

return lookup;
    }
}

```
