Spring Boot LDAP - Eror code 80 when trying to auth users - spring-boot

I am trying to auth users through secured adlds server from a spring boot application, and I am facing an issue for 2 weeks now, and no solutions found in the internet worked for me.
First I had an error that says that I need to bind the authentication before successful operation. I added the right properties to the context source but now I am getting an error code 80 which gives me no clues on the error.
Here is my code:
Application.yml
spring:
ldap:
url: ldaps://<hostname>:636
base: DC=<dc>>,DC=<dc>
username: CN=<cn>>,OU=Privileged,OU=<ou>,OU=<ou>,OU=<ou>,DC=<dc>,DC=<dc>
password: <secret>
base-environment:
com.sun.jndi.ldap.connect.timeout: 500
management:
health:
ldap:
enabled: false
Configuration.java
#Bean
#DependsOn("frameworkInstance")
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldaps://<hostname>:636");
contextSource.setBase("<base>");
contextSource.setUserDn("CN=<cn>,OU=<ou>>,OU=<ou>>,OU=<ou>>,OU=<ou>,DC=<dc>,DC=<dc>>");
contextSource.setPassword("<secret>");
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
#DependsOn("frameworkInstance")
public LdapTemplate ldapTemplate() {
return new LdapTemplate(contextSource());
}
My auth process :
Filter filter = new EqualsFilter("cn", "<cn>");
ldapTemplate.authenticate(LdapUtils.emptyLdapName(), filter.encode(), "<secret>");
The error code is :
Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 80 - 80090304: LdapErr: DSID-0C090447, comment: AcceptSecurityContext error, data 20ee, v3839\u0000]
I tried everything for a couple of days but nothing ... The account used for the "bind" and for the authentication is the same, to ensure that the auth will be succesfull. Keep in mind that the words between chevrons are hidden because of production environment, I am not allowed to display credentials, etc.
Do you have please any clues to resolve that issue ? it's very critical
Best regards,

In the error message, the data 20ee indicates the Windows System Error Code. According to the Microsoft documentation, that is:
ERROR_DS_INTERNAL_FAILURE
8430 (0x20EE)
The directory service encountered an internal failure.
I don't think that indicates any problem with your code. It sounds more like a problem with your Active Directory environment.
Have you tried connecting via regular LDAP rather than LDAPS? (ldap://<hostname>). If that works, then it would indicate a problem with the LDAPS configuration.
As a side note, if you indicate ldaps:// in the path, you don't need to include :636, since that is the default LDAPS port.

Related

Spring Security OAuth2 client with authorization_code grant - How to handle token request?

I am building a Spring Boot application using version 2.3.4 with spring-boot-starter-oauth2-client and spring-boot-starter-security dependencies.
I am trying to implement the JIRA Tempo plugin OAuth support.
I have it partially working using the following properties:
spring.security.oauth2.client.registration.tempo.redirect-uri=http://localhost:8080
spring.security.oauth2.client.registration.tempo.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.tempo.client-id=<the-client-id>
spring.security.oauth2.client.registration.tempo.client-secret=<the-client-secret>
spring.security.oauth2.client.registration.tempo.provider=tempo
spring.security.oauth2.client.provider.tempo.authorization-uri=https://mycompany.atlassian.net/plugins/servlet/ac/io.tempo.jira/oauth-authorize/?access_type=tenant_user
spring.security.oauth2.client.provider.tempo.token-uri=https://api.tempo.io/oauth/token/
and this config:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests(expressionInterceptUrlRegistry -> expressionInterceptUrlRegistry.anyRequest().authenticated())
.oauth2Login();
}
When I access http://localhost:8080, it redirects to JIRA/Tempo and shows the approval dialog there to grant access to the Tempo data for my application. I can grant access, but after that, it just redirects again to that page instead of showing my own application.
With debugging, I noticed that there is a redirect to http://localhost:8080/?code=.... but Spring Security is not handling that. What else do I need to configure?
I also tried to set some breakpoints in DefaultAuthorizationCodeTokenResponseClient, but they are never hit.
UPDATE:
I changed the redirect-uri to be:
spring.security.oauth2.client.registration.tempo.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}
(and I changed the Redirect URIs setting in Tempo to http://localhost:8080/login/oauth2/code/tempo).
This now redirects back to my localhost, but it fails with authorization_request_not_found.
UPDATE 2:
The reason for the authorization_request_not_found seems to be mismatch in HttpSessionOAuth2AuthorizationRequestRepository.removeAuthorizationRequest(HttpServletRequest request) between what is in the authorizationRequests and the stateParameters.
Note how one ends with = and the other with %3D, which makes them not match. It is probably no coincidence that the URL encoding of = is %3D. It is unclear to me if this is something that is a Spring Security problem, or a problem of the Tempo resource server, or still a misconfiguration on my part.
The redirect-uri property should not point to the root of your application, but to the processing filter, where the code after redirect is processed.
Best practice for you would be to leave the redirect-uri alone for the time being. Then it will default to /login/oauth2/code/* and this Url is handled by org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.

How to configure Spring Boot to use OIDC while app is behind an SSL termination proxy

I am trying to configure a Spring Boot app to use OIDC. The server is behind an SSL termination proxy.
Here are the properties I use:
spring:
security:
oauth2:
client:
provider:
oidc:
authorization-uri: https://example.org/oidc/oauth2/authorize
token-uri: https://example.org/oidc/oauth2/access_token
user-info-uri: https://example.org/oidc/oauth2/userinfo
jwk-set-uri: https://example.org/oidc/oauth2/connect/jwk_uri
custom-params: param_name1,param_value1,param_name2,param_value2,nonce,123456789
registration:
oidc:
client-id: myclientid
client-secret: myclientsecret
authorization-grant-type: authorization_code
scope:
- openid
- email
- profile
redirect-uri: https://mydomain/myapp/login/oauth2/code/oidc
Here's where it goes wrong:
1. The OIDC server requires a nonce param to be added to the request URL
I have solved this by using a custom OAuth2AuthorizationRequest that reads the custom-params property and appends those values to the request URL
2. The OidcAuthorizationCodeAuthenticationProvider throws an exception caused by invalid_redirect_uri_parameter
I have tried many approaches to fix this.
I have tried creating a filter that adds the X-Forwarded-Proto to the request (because the proxy doesn't handle that).
The headers are added, I have also added the following properties:
server:
forward-headers-strategy: native
tomcat.protocol-header: x-forwarded-proto
But it doesn't seem to work.
OidcAuthorizationCodeAuthenticationProvider still throws an exception because this condition is false:
!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())
I have debugged the code and the only difference is one being http and the other https.
I have found a VERY hacky solution that I don't like at all, which is another filter that modifies the URL just for that particular URL.
I would prefer a more elegant solution.
3. When using the custom nonce parameter, the OidcAuthorizationCodeAuthenticationProvider throws an exception cause by invalid_nonce
Now I am stuck. I considered writing my own Authentication Provider, but I have no guarantee that mine will be picked up before the OIDC one provided by Spring.
And with the nonce, it's a catch 22:
if I don't use the custom param, I couldn't find a way to make Spring add the nonce to the request
if I use that one, Spring doesn't recognize it when it's part of the JWT and freaks out
Any help would be GREATLY appreciated, as this has been driving me nuts for days if not weeks.
Thank you.
EDIT
The 2 urls that are compared in case 2 come from:
OAuth2AuthorizationRequest
OAuth2AuthorizationResponse
OAuth2AuthorizationRequest is built in the
OAuth2AuthorizationRequestRedirectFilter at the following line:
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestResolver.resolve(request);
The redirect uri is built in DefaultOAuth2AuthorizationRequestResolver.expandRedirectUri() which calls
UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
OAuth2AuthorizationResponse is built in the OAuth2LoginAuthenticationFilter.attemptAuthentication() which also calls
UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
and then
OAuth2AuthorizationResponseUtils.convert(params, redirectUri)
I will double check, but I don't remember UriComponentsBuilder.adaptFromForwardedHeaders(HttpHeaders headers) being called when building these URLs.
And even if that works, that still leaves the nonce issue :(
We stumbled upon the same problem , the problem was mainly because our server was behind a reverse proxy, and it seems the proxy changed the url somehow causing this check to fail
!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())
this line was removed in later versions of spring security , at commit
24500fa3ca23aa23ede86dfcfe02113671d5b8bc
commit at github
which was introduced on Dec 6, 2019 and was in spring security release 5.1.13
so the solution was to upgrade spring boot to at least 2.1.17 for spring boot 2.1.X line of versions.
while the OP said he can't upgrade his libraries, I hope this can help those who can.
We also did the solution mentioned above by Kavithakaran Kanapathippilla and configured our reverse proxy to add X-forwarded-proto http headers , also i believed we configured spring boot application.properties to check for them
spring boot documentation for working behind proxies

Jhipster Health Endpoint fails when mailserver not connected

JHipster / Spring boot provides a nice endpoint /management/health, where it aggregates health information for subsystems like db, disk, and mail.
Unfortunately, when the connection to the mail server fails, the whole endpoint fails. So you do not get information what has failed.
I get a strack trace like this:
o.s.b.a.health.MailHealthIndicator : Health check failed
com.sun.mail.util.MailConnectException: Couldn't connect to host, port: XXXX, NNNN25025; timeout -1
...
at org.springframework.boot.actuate.health.MailHealthIndicator.doHealthCheck(MailHealthIndicator.java:40)
at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:43)
at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:68)
at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:85)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getCurrentHealth(HealthMvcEndpoint.java:177)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getHealth(HealthMvcEndpoint.java:166)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(HealthMvcEndpoint.java:143)
This is spring boot 1.5.9
Where should I fix this, so that the exception is catched and instead a an error status is returned?
You have to turn on your SMTP server or disable checks to it.
To disable checks to SMTP server:
management.health.mail.enabled=false
To disable checks to all server:
management.health.defaults.enabled=false
for more information, see http://www.briansjavablog.com/2017/09/health-checks-metric-s-more-with-spring.html
I believe you can handle this error with the ExceptionHandler for 1.5.9 version of Spring Boot since the newer version there is no such problem:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(MailConnectException.class)
public ResponseEntity<?> mailExceptionHandler(MailConnectException e) {
// Do your treatment ...
} ...
}

Authentication with Spring-Boot-Admin and Eureka discovery

SBA version 2.0.1
Spring-Cloud Finchley.RELEASE
I have some services registered in Eureka. The services are Spring-Boot apps, and have their actuators secured by HTTP basic auth. The service actuators are at /actuator. The services are working and I can interact with their actuators via Postman and curl. SBA connects to Eureka and discovers the services, but they are always in a down (red) state, except for the SBA application itself, which is shown just fine as green in the SBA console, and I am able to click on it and see it's properties.
When I click on one of the service instances, I am prompted for credentials. I'm not sure what credentials to use, so I use the credentials for the service actuator. I already have these credentials in the metadata-map as shown in the docs, but I am still prompted for credentials anyway. This always results in showing the Whitelabel Error Page, with an error message like this:
Mon Jun 25 12:40:57 CDT 2018 There was an unexpected error
(type=Method Not Allowed, status=405). Request method 'POST' not
supported
Though I note the url for that error is apparently on the SBA instance intself, not the remote service. The url decodes to this: http://localhost:8080/#/instances/9207aa5fc06b/
But I see this in the log for the service, so apparently an unauthenticated request is making it to the remove service:
[2018-06-25 12:16:54.242] - DEBUG - [http-nio-8380-exec-7]
[AUTHENTICATION_SERVICE_DEV,8dc8165d4f77be7c,8dc8165d4f77be7c,false]
--- [nio-8380-exec-7] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jun 25 12:16:54 CDT 2018, status=401,
error=Unauthorized, message=Unauthorized, path=/actuator/health}] as
"application/vnd.spring-boot.actuator.v2+json" using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#30c8681]
And this in the SBA log:
2018-06-25 12:39:40.884 ERROR [SERVICES_ADMIN_CONSOLE_LOCAL,,,] 20728
--- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception
java.io.IOException: An established connection was aborted by the
software in your host machine
This is the root of my confusion, I'm not sure what credentials I need or even what I am authenticating to. I have provided the credentials to remote service in properties as well as in the login form, and it doesn't work.
When I click on the SBA application in the SBA console, it works as expected. So this seems to be related to authenticating to a remote actuator, but I can't figure out what the problem is.
Server:
#Configuration
#EnableAutoConfiguration
#EnableEurekaClient
#EnableAdminServer
public class ServiceAdmin {
public static void main(String[] args) {
SpringApplication.run(ServiceAdmin.class, args);
}
#Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
.and().csrf().disable();
}
}
}
SBA Config:
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.info.git.mode=full
management.endpoint.shutdown.enabled=true
spring.security.user.name=actuator
spring.security.user.password=password
spring.security.user.roles=ACTUATOR
eureka.instance.leaseRenewalIntervalInSeconds=10
eureka.instance.health-check-url-path=/actuator/health
eureka.instance.metadata-map.user.name=actuator
eureka.instance.metadata-map.user.password=password
eureka.client.registryFetchIntervalSeconds=5
eureka.client.serviceUrl.defaultZone=http://svcregistry1.mycompany.com/eureka/,http://svcregistry2.mycompany.com
For anyone coming to this question, being as puzzled as I, to clear up this answer.
I'm having Eureka and Springboot admin server/ui in the same application
All the services that will register into eureka AND springboot admin, will need their own /actuator credentials present as metadata :
eureka.instance.metadata-map.user.name = ${endpoints.user.name}
eureka.instance.metadata-map.user.password = ${endpoints.user.password}
This post cleared up a few things.
https://zoltanaltfatter.com/2018/05/15/spring-cloud-discovery-with-spring-boot-admin/
The problem here was I failed to understand the docs. The eureka credentials in the metadataMap have to be provided by the monitored application at registration time. Not provided in the SBA config.

How to connect with an external/online LDAP server using Spring Boot?

I am trying to integrate LDAP based login in my Spring Boot application.
As initial step, I am trying to use this LDAP server (http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/).
But, I am unable to successfully connect with the server and getting this error.
nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
I am using this information in configuration class.
authenticationManagerBuilder.ldapAuthentication()
.contextSource().url("ldap://ldap.forumsys.com:389/dc=example,dc=com")
.managerDn("cn=read-only-admin,dc=example,dc=com").managerPassword("password")
.and()
.userSearchBase("ou=mathematicians")
.groupSearchBase("ou=mathematicians")
.userSearchFilter("(cn={0})");
And this is my application.properties file for this project.
spring.ldap.urls=ldap.forumsys.com:389
spring.ldap.base=cn=read-only-admin,dc=example,dc=com
spring.ldap.password=password
Can anyone provide a working configuration for a Spring Boot application using an LDAP server?
As I was getting this error code from LDAP server.
LDAP: error code 49 - Invalid Credentials
The issue was with information that I was sending to LDAP server for opening a communication channel. So when I changed my request to a different object it started to working.
Here is the correct reqeust that we need to send from Spring to LDAP server.
authenticationManagerBuilder
.ldapAuthentication()
.userDetailsContextMapper(inetOrgPersonContextMapper())
.userSearchFilter("(uid={0})")
.userSearchBase("dc=example,dc=com")
.groupSearchBase("ou=mathematicians,dc=example,dc=com")
.groupSearchFilter("cn={0}")
.contextSource()
.url("ldap://ldap.forumsys.com")
.port(389)
.managerDn("cn=read-only-admin,dc=example,dc=com")
.managerPassword("password");
This is the correct configuration:
authenticationManagerBuilder
.ldapAuthentication()
.userSearchFilter("(uid={0})")
.userSearchBase("dc=example,dc=com")
.groupSearchFilter("uniqueMember={0}")
.groupSearchBase("ou=mathematicians,dc=example,dc=com")
.userDnPatterns("uid={0}")
.contextSource()
.url("ldap://ldap.forumsys.com:389")
.managerDn("cn=read-only-admin,dc=example,dc=com")
.managerPassword("password");
Use below application property.
ldap.enabled = true
####### LDAP TEST##############
ldap.urls= ldap://ldap.forumsys.com:389/
ldap.base.dn= dc=example,dc=com
ldap.username= cn=read-only-admin,dc=example,dc=com
ldap.password= password
ldap.user.dn.pattern = uid={0}

Resources