Spring Security : LDAP Authentication and Search - spring

I want to convert a normal Spring LDAP integration to Spring Security application. I have the application context as this.
<ldap:context-source
url="ldap://euro.mo.xyz.com:389"
base="ou=prod,dc=euro,dc=mo,dc=xyz,dc=com"
username="mydomain\mohan06"
password="hotStar56" />
When I used passwordCompare and userDn, then I got the following exception
javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C09075A, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1]
After seeing some advice online
I tried using managerDn like the following
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userDnPatterns("OU=prod,DC=euro,DC=mo,DC=xyz,DC=com")
.userSearchFilter("sAMAccountName={0}")
.userSearchBase("OU=prod,DC=euro,DC=mo,DC=xyz,DC=com")
.contextSource()
.url("ldap://ptklt.euro.mo.xyz.com:389")
.managerDn("CN=mydomain\\\\mohan06,OU=prod,DC=euro,DC=mo,DC=xyz,DC=com")
.managerPassword("hotStar56")
.root("OU=prod,DC=euro,DC=mo,DC=xyz,DC=com");
But now I get the following error, even though my credentials are fine.
AcceptSecurityContext error, data 52e, v1db1 ]; nested exception is javax.naming.AuthenticationException
Should I need to use different credentials for password compare and managerDn?

Related

Confiure LDAPS using Spring Boot without LDIF

I am using the below code:
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},OU=b")
.groupSearchBase("OU=Service Account")
.contextSource()
.url("ldaps://AD.b.com:636/DC=b,DC=com")
.and()
.passwordCompare()
.passwordEncoder(new BCryptPasswordEncoder())
.passwordAttribute("userPassword");
}
I am getting errors after inserting username and password which are provided by Admin.
Error log:
2022-04-11 10:05:09.086 ERROR 1969 --- [nio-8083-exec-9] w.a.UsernamePasswordAuthenticationFilter : An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: Connection or outbound has closed; nested exception is javax.naming.CommunicationException: Connection or outbound has closed [Root exception is java.net.SocketException: Connection or outbound has closed]; remaining name 'uid=test,OU=b'

Spring Boot #RequestScope and Hibernate schema based multi-tenancy

I'm working on a schema based multi-tenant app, in which I want to resolve the Tenant Identifier using a #RequestScope bean. My understanding is that #RequestScope uses/injects proxies for the request scoped beans, wherever they are referred (e.g. in other singleton beans). However, this is not working in the #Component that implements CurrentTenantIdentifierResolver and I get the following error when I start my service,
Caused by: org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.userContext': Scope 'request' is not active for the current thread;
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Following are the relevant pieces of code.
#Component
public class CurrentTenant implements CurrentTenantIdentifierResolver {
#Autowired
private UserContext userContext;
#Override
public String resolveCurrentTenantIdentifier() {
return Optional.of(userContext)
.map(u -> u.getDomain())
.get();
}
#Component
#RequestScope
public class UserContext {
private UUID id;
private String domain;
My questions,
Isn't the proxy for the #RequestScope injected (by default)? Do I need to do anything more?
Is Hibernate/Spring trying to establish a connection to the DB at startup (even when there is no tenant available)?
Hibernate properties:
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
properties.remove(AvailableSettings.DEFAULT_SCHEMA);
properties.put(AvailableSettings.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
For the time being, I'm preventing the NullPointerException by checking if we are in the RequestContext. However, a connection still gets established to the master database (although I've explicitly specified the dialect and am not specifying hbm2ddl.auto). Since this connection is not associated with any schema, I'd like to avoid making it, so that it does not look for any tables that it won't find anyways.
What seems to be happenning is that when a HTTP request is received, hibernate is trying to resolve the current tenant identifier, even before my #RequestScope bean is created (and even before my #RestController method is called.) If a provide the default connection to the databse, I then get the following error. If I don't provide a connection, it throws an exception and aborts.
2021-09-26 11:55:44.882 WARN 19759 --- [nio-8082-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42P01
2021-09-26 11:55:44.882 ERROR 19759 --- [nio-8082-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: relation "employees" does not exist
Position: 301
2021-09-26 11:55:44.884 ERROR 19759 --- [nio-8082-exec-2] o.t.n.controller.EmployeeController : Exception: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet

Spring cloud GCP com.google.cloud.storage.StorageException access_token not found error

Spring boot-2.3.10, Spring Cloud Gcp: 1.2.8
I'm trying to access specific image pattern **(/resources/images/specific_folder/****) from GC Storage. For that I wrote the resource handler as shown below:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("Setting the resource location {}", gcStorageLocation);
registry.addResourceHandler("/resources/images/specific_folder/**").addResourceLocations("gs:bucket_name/storage/images/specific_folder/").setCachePeriod(3600).resourceChain(true)
.addResolver(new GcStorageResolver());
}
GcStorageResolver.java extends AbstractResourceResolver.java
#Override
protected Resource resolveResourceInternal(#Nullable HttpServletRequest request, String requestPath, List<? extends Resource> locations,
ResourceResolverChain chain) {
log.info("resolveResourceInternal called for request: {}, requestPath: {}", request.getRequestURL(), requestPath);
return getResource(requestPath, request, locations);
}
I verified that a valid GoogleStorageResource is being returned along with credential. But somewhere in the spring chain, I'm getting the below error:
2021-06-25 15:40:23.366 ERROR 4676 --- [nio-8080-exec-1]
o.a.c.c.C.[.[.[.[dispatcherServlet] 175 : Servlet.service() for
servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed; nested exception is
com.google.cloud.storage.StorageException: Error parsing token refresh
response. Expected value access_token not found.] with root cause
java.io.IOException: Error parsing token refresh response. Expected
value access_token not found. at
com.google.auth.oauth2.OAuth2Utils.validateString(OAuth2Utils.java:113)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:449)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:157)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:145)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.auth.oauth2.ServiceAccountCredentials.getRequestMetadata(ServiceAccountCredentials.java:603)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.auth.http.HttpCredentialsAdapter.initialize(HttpCredentialsAdapter.java:91)
~[google-auth-library-oauth2-http-0.22.1.jar:?] at
com.google.cloud.http.HttpTransportOptions$1.initialize(HttpTransportOptions.java:159)
~[google-cloud-core-http-1.94.0.jar:1.94.0] at
com.google.cloud.http.CensusHttpModule$CensusHttpRequestInitializer.initialize(CensusHttpModule.java:109)
~[google-cloud-core-http-1.94.0.jar:1.94.0] at
com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:88)
~[google-http-client-1.38.0.jar:1.38.0]
Not sure what's going on here. Any pointers?

Getting Postgres Table Not Found Error with #ReadOnly Annotation in Spring Boot

I am getting the error PSQLException: ERROR: relation "schema.tableName" does not exist.
I have a GET API in spring which fetches data from a table. This API internally uses a custom method to access data using JpaReporitory. This custom method is annotated with #ReadOnly and #Transactional annotations since this API only fetches data from table. This gives me the table not found error.
But when I remove the #ReadOnly annotation, the API works just fine.
Below are the signatures of the said API and the custom method that it uses:
API:
#GetMapping("/houses/{houseId}/furnitures")
public List<Furnitures> getFurnitureslist(#PathVariable("houseId") long houseId) throws InterruptedException, ExecutionException {
return this.houseService.getFurnituresList(houseId);
}
Custom method:
#Transactional
#ReadOnly
public List<Asset> getTripPicklist(long tripId){
//Bunch of read operations using jpa repository.
}
This gives me an error trace as below:
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: org.postgresql.util.PSQLException: ERROR: relation "schema.tableName" does not exist
But when I remove the #ReadOnly annotation from my custom method, the API works fine and I am able fetch the expected results from the database. What am I doing wrong?

Spring Security LDAP - Using AuthenticationManagerBuilder rejects context

I've managed to successfully use LDAP to retrieve users from an ActiveDirectory.
However, to do so I had to manually instantiate the BaseLdapPathContextSource like this:
Working Spring Security configuration:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapProperties.getServer());
contextSource.setUserDn(ldapProperties.getUserDN());
contextSource.setPassword(ldapProperties.getPassword());
contextSource.setBase(ldapProperties.getRootDN());
contextSource.afterPropertiesSet();
// #formatter:off
auth.ldapAuthentication()
.contextSource(contextSource)
.userDnPatterns(new String[]{ ldapProperties.getUserOU() })
.userSearchBase("")
.userSearchFilter("(sAMAccountName={0})")
.ldapAuthoritiesPopulator((userData, username) ->
Collections.singleton(new SimpleGrantedAuthority("CLIENT"))
);
// #formatter:on
}
If instead of this I use the methods provided by the builder, then every login attempt gets rejected.
Not working Spring Security configuration:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.contextSource()
.url(ldapProperties.getServer())
.managerDn(ldapProperties.getUserDN())
.managerPassword(ldapProperties.getPassword())
.root(ldapProperties.getRootDN())
.and()
.userDnPatterns(new String[]{ ldapProperties.getUserOU() })
.userSearchBase("")
.userSearchFilter("(sAMAccountName={0})")
.ldapAuthoritiesPopulator((userData, username) ->
Collections.singleton(new SimpleGrantedAuthority("CLIENT"))
);
}
I've debugged the ContextSourceBuilder, and it is building a DefaultSpringSecurityContextSource too, similarly of how I am doing it.
The only difference between the manually built context and the one provided by the builder seems to be that objectPostProcessors are applied to it after beign built. However, most of them just autowire beans.
Log provided on a failed authentication (that should have succeeded):
2018-09-25 15:45:25.679 DEBUG 10784 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
2018-09-25 15:45:25.680 DEBUG 10784 --- [nio-8080-exec-3] o.s.s.l.a.LdapAuthenticationProvider : Processing authentication request for user: mcurrao
2018-09-25 15:45:25.689 DEBUG 10784 --- [nio-8080-exec-3] o.s.s.l.a.BindAuthenticator : Attempting to bind as ou=factory
2018-09-25 15:45:25.689 DEBUG 10784 --- [nio-8080-exec-3] s.s.l.DefaultSpringSecurityContextSource : Removing pooling flag for user ou=[my_ou]
2018-09-25 15:45:25.694 DEBUG 10784 --- [nio-8080-exec-3] o.s.s.l.a.BindAuthenticator : Failed to bind as OU=[my_ou]: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090400, comment: AcceptSecurityContext error, data 52e, v1db1
Note: [my_ou] is actually being replaced as my own ou. But as I don't know how sensitive this is, better not risk it.
Note 2: This log is only provided by enabling Spring debug logging. No exception is thrown nor information is given on a login attempt if said debug is not enabled.
This error codes seem to be just "Couldn't find your user" errors.
TL;DR: LDAP authentication does not work if I use the provided contextSource() builder, forcing me to instantiate a context source.

Resources