LDAP Authentication with Spring - getting PartialResultException - spring

I am following this article on setting LDAP Authentication with Spring
Now I can login to the application, but I get this exception:
Unprocessed Continuation Reference(s); nested exception is javax.naming.PartialResultException:
Unprocessed Continuation Reference(s); remaining name 'DC=XEROX,DC=AD,DC=XEROX,DC=com'
Caused by: javax.naming.PartialResultException: Unprocessed Continuation Reference(s)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2917) ~[na:1.8.0_144]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2891) ~[na:1.8.0_144]
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1846) ~[na:1.8.0_144]
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1769) ~[na:1.8.0_144]
according to other articles I read, I need to set the referral to follow, setReferral("follow");
But I am not sure where to add this to this code:
String completeUrl = new StringBuffer(this.url).append(":")
.append(this.port)
.append("/")
.append(this.contextRoot)
.toString();
auth.ldapAuthentication()
.userSearchFilter(userSearchFilter)
.userDnPatterns(userDnPatterns)
.contextSource()
.url(completeUrl)
.managerDn(managerDn)
.managerPassword(managerPassword);

You should create your own contextSource, something like:
#Bean("internalLdapContextSource")
public LdapContextSource getLdapContextSource() {
String ldapUrl = env.getProperty("ldap.server");
String managerDn = env.getProperty("ldap.manager.distinguished.name");
String managerPassword = env.getProperty("ldap.manager.password");
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(ldapUrl);
contextSource.setUserDn(managerDn);
contextSource.setPassword(managerPassword);
Map<String, Object> baseEnvironmentProperties = new HashMap<>();
baseEnvironmentProperties.put("java.naming.referral", "follow");
contextSource.setBaseEnvironmentProperties(baseEnvironmentProperties);
return contextSource;
}
You can use setBaseEnvironmentProperties method as shown in the sample or setReferral ( both works fine ).
Finally use
.contextSource(getLdapContextSource())

Related

Springboot #Value not loading

In my sample Springboot project on Github, the #Value property won't get loaded when starting the application. I cannot explain the strange behavior and hope that anyone could help me please to solve it and to avoid such stupid errors?
#RestController
public class PostClient {
#Value(value = "${target.uri}")
public String uri;
private RestTemplate restTemplate = new RestTemplate();
private HttpHeaders headers = new HttpHeaders();
public PostClient() {}
public HttpStatus postNumberPlate(CamImage camImage) {
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("numplate", camImage.getIdentifier());
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String,
Object>>(map, headers);
ByteArrayResource resource = new ByteArrayResource(camImage.getData()) {
#Override
public String getFilename() {
return camImage.getIdentifier() + ".png";
}
};
map.add("image", resource);
System.out.println(uri);
ResponseEntity<String> result = restTemplate.exchange(uri,
HttpMethod.POST,
requestEntity, String.class);
return result.getStatusCode();
}
}
The application.properties
target.uri=http://localhost:9001/postoffice
I read that the #Value is a core functionality of Springboot and should work fine. My project is so small, that I wonder what might broke the framework's behavior of automatic value replacement. I found different and similar questions regarding the #Value issue, but a real explanation cannot be found.
I tried to use a #Component Class with getters/setters and tried to #Autowire it into the shown Class, but that didn't work, too.
I'd like to go the proposed way of the Springboot reference, because any hard-coded String will result in problems, when building docker containers, where I must pass a configuration parameter. So I cannot only rely on a fixed application.properties in the classpath.
EDIT:
Running the application looks like:
shell:>one
Euro Plate # unimportant sysout
CamImage [identifier=BNAYG63, data=[B#4f4c4c4b] # generated plate
null # from sysout here should be the address!!
URI is not absolute
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
shell:>stacktrace
java.lang.IllegalArgumentException: URI is not absolute
at java.base/java.net.URL.fromURI(URL.java:674)
at java.base/java.net.URI.toURL(URI.java:1116)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:145)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:87)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:731)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579)
at dev.semo.npgen.service.PostClient.postNumberPlate(PostClient.java:45)
at dev.semo.npgen.shell.NumberplateClientCommands.one(NumberplateClientCommands.java:62)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
at org.springframework.shell.Shell.evaluate(Shell.java:180)
at org.springframework.shell.Shell.run(Shell.java:142)
at org.springframework.shell.jline.InteractiveShellApplicationRunner.run(InteractiveShellApplicationRunner.java:84)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:770)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at dev.semo.npgen.NpgenApplication.main(NpgenApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
I have pulled your source from github and tested. Initially it was throwing error as you mentioned. After I have changed like below it is working fine. You should to autowire the PostClient, because the scanning happened and loaded the defaults while you started the application.
#ShellComponent
public class NumberplateClientCommands {
#Autowired
private PostClient postClient;
.....
#ShellMethod("Sends one simple POST request.")
public String one() throws FileNotFoundException {
NumberPlateUtility np = new NumberPlateUtility();
HttpStatus response = postClient.postNumberPlate(np.completeImage());
if (response == HttpStatus.ACCEPTED) {
return "Request sent successfully.";
}
return String.format("Request failed: %s", response.getReasonPhrase());
}
.......
}
Follow this Code Snip
#Value("${target.uri}")
private String uri;

Spring Boot LDAP

I am working on Spring Boot application in which I need to verify that is user belong to domain or not?
To check it I want to verify the username entry though ldap.
Below is code for creating LDAP Configuration:
#Bean
public LdapContextSource contextSource(String url, String port, String baseName, String uName, String password) {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(url + ":" + port));
contextSource.setBase(baseName);
contextSource.setUserDn(uName);
contextSource.setPassword(password);
contextSource.setReferral("follow");
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(String url, String port, String baseName, String uName, String password) {
final LdapTemplate ldapTemplate = new LdapTemplate(contextSource(url, port, baseName, uName, password));
return ldapTemplate;
}
I am getting below exception
default task-101) Error/Exception occured while login nested exception is javax.naming.PartialResultException [Root exception is javax.naming.ServiceUnavailableException: DomainDnsZones.magna.global:389; socket closed]
In ldapTemplate method add statement ldapTemplate.setIgnorePartialResultException(true); for ignoring partial result exception.
The connection to LDAP is closed . You need to add the SSL certificate for establishing the connection and check if there are any firewall openings required .

Spring MockMvc Post Test: Comparison Failure

I am trying to perfom a Post test on this method with mockito
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addBookPost(#ModelAttribute("book") Book book, HttpServletRequest request, Model model) {
bookService.save(book);
MultipartFile bookImage = book.getBookImage();
try {
byte[] bytes = bookImage.getBytes();
String name = book.getId() + ".png";
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File("src/main/resources/static/image/book/" + name)));
stream.write(bytes);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
So far I have done this below but my result shows I have two different instance of the object save , that is the book I save and expect is not the book I am getting .
#Test
public void addBookClicked() throws Exception {
Book book1 = new Book();
// when(bookService.save(anyObject())).thenReturn(anyObject());
mockMvc.perform(post("/book/add").with(user("admin").password("admin").roles("USER", "ADMIN"))
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML))
.andExpect(status().is3xxRedirection()).andDo(print())
.andExpect(view().name("redirect:bookList"))
.andReturn();
Mockito.verify(bookService).save(book1);
}
And what can I do with the try and catch block in the test because it also gives an error in test Null pointer - may be because I am not testing or adding image to the test .
error log
MockHttpServletResponse:
Status = 302
Error message = null
Argument(s) are different! Wanted:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#4acc5dff
);
-> at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
Actual invocation has different arguments:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#10c72a6f
);
-> at com.valentine.adminportal.controller.BookController.addBookPost(BookController.java:50)
Comparison Failure: <Click to see difference>
Argument(s) are different! Wanted:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#4acc5dff
);
-> at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
Actual invocation has different arguments:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#10c72a6f
);
-> at com.valentine.adminportal.controller.BookController.addBookPost(BookController.java:50)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springf
In addBookClicked you are not actually posting book1 to your controller. The book1 instance in that test method is only referenced (1) where it is created and (2) where it is verified.
You must pass the serialised form of book1 in the body of the mockMvc.perform() invocation.
Here's an example:
mockMvc.perform(post("/book/add")
.with(user("admin").password("admin").roles("USER", "ADMIN"))
.accept(MediaType.TEXT_HTML)
.content(objectMapper.writeValueAsString(book1))
.contentType(MediaType.TEXT_HTML))
.andExpect(status().is3xxRedirection()).andDo(print())
.andExpect(view().name("redirect:bookList"))
.andReturn();
The objectMapper in this example is an instance of Jackson's ObjectMapper and its responsibility is to serialise the book1 instance to JSON for inclusion in the request body.

How to pass a List<Object> in Rest Template?

I need to write a client code to call a method in a webservice and this is my client code.
#HystrixCommand
public List<Location> saveLocation (List<LocationDTO> locationDTO) {
HttpEntity<List<LocationDTO>> httpEntity = new HttpEntity<>(locationDTO);
ResponseEntity<List<Location>> response =
restTemplate.exchange(locationProperties.getBaseURL(),HttpMethod.POST,
httpEntity,new ParameterizedTypeReference<List<Location>>() {
});
return getResponseBody(response);
}
For which I write Junit to test this piece of code.
#Test
public void saveLocationTest() throws Exception {
List<LocationDTO> locationList = new ArrayList<>();
LocationDTO locationDTO = new LocationDTO();
locationList.add(locationDTO);
Location location = new Location();
location.setLocationID(100);
mockServer.expect(requestTo(baseURL)).andExpect(method(HttpMethod.POST))
.andRespond(withSuccess("{\"locationID\":100}",MediaType.APPLICATION_JSON));
List<Location> response = locationClient.saveLocation(locationList);
assertEquals(response, location);
}
But I get the following error when I run the Junit, which also means my client code is wrong.
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not >deserialize instance of java.util.ArrayList out of START_OBJECT token
at [Source: java.io.ByteArrayInputStream#175b9425; line: 1, column: 1]
Rest Template and junit works fine if I just pass LocationDTO instead of List<LocationDTO>.Could anyone please help me with this?

Spring rest template 401 error response

I have a rest controller answering on http://localhost:8080/documents.
I should have an authorization header to call it.
So in my client code i have :
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "myToken");
HttpEntity entity = new HttpEntity(null, headers);
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
response = restTemplate.exchange("http://localhost:8080/documents", HttpMethod.GET, entity, Document[].class);
Everything works fine.
After that i want to test the errors.
So, i remove the authorization header.
When i test with a tool like postman, i receive the 401 response.
But with my rest template, i only receive an IllegalArgumentException.
I alse have tested the ResponseErrorHandler.
public class MyErrorHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
return false; //i've also tried return true
}
#Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
String theString = IOUtils.toString(clientHttpResponse.getBody());
FunctionalTestException exception = new FunctionalTestException();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("code", clientHttpResponse.getStatusCode().toString());
properties.put("body", theString);
properties.put("header", clientHttpResponse.getHeaders());
exception.setProperties(properties);
throw exception;
}
}
and in my client i have
restTemplate.setErrorHandler(new MyErrorHandler());
It didn't work.
So my question is how to find my 401 error response using the rest template.
Here is the exception :
java.lang.IllegalArgumentException: invalid start or end
and the stack trace :
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1455)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
sun.net.www.protocol.http.HttpURLConnection.getHeaderField(HttpURLConnection.java:2979)
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:489)
org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:84)
org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580)
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:498)
org.boite.dq.steps.UnauthorizedUser.callListCategories(UnauthorizedUser.java:61)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.jbehave.core.steps.StepCreator$ParametrisedStep.perform(StepCreator.java:733)
org.jbehave.core.embedder.PerformableTree$FineSoFar.run(PerformableTree.java:346)
org.jbehave.core.embedder.PerformableTree$PerformableSteps.perform(PerformableTree.java:1088)
org.jbehave.core.embedder.PerformableTree$AbstractPerformableScenario.performRestartableSteps(PerformableTree.java:953)
org.jbehave.core.embedder.PerformableTree$NormalPerformableScenario.perform(PerformableTree.java:992)
org.jbehave.core.embedder.PerformableTree$PerformableScenario.perform(PerformableTree.java:902)
org.jbehave.core.embedder.PerformableTree$PerformableStory.performScenarios(PerformableTree.java:825)
org.jbehave.core.embedder.PerformableTree$PerformableStory.perform(PerformableTree.java:798)
org.jbehave.core.embedder.PerformableTree.performCancellable(PerformableTree.java:422)
org.jbehave.core.embedder.PerformableTree.perform(PerformableTree.java:393)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:292)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:266)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
The crash is happening in HttpURLConnection::getHeaderField so I'd suspect that one of your response headers is malformed (not what HttpURLConnection expects it to be). Usually a 401 response comes with a WWW-Authenticate response header pointing the agent to the authentication methods supported by the service. I'd suspect that this header causes the crash.
A bug report in Jersey's issue-tracker shows that HttpURLConnection puts some constraints on the WWW-Authentication header format. In this particular case the value causing a similar crash is oauth_problem=token_rejected. A workaround proposed there is:
Workaround is to send valid header values (spec compliant) or using the ApacheConnector

Resources