I am running into issues while trying to access kerberos SPNEGO authenticated resource using spring rest client. I am using KerberosRestTemplate.
From the docs
Leave keyTabLocation and userPrincipal empty if you want to use cached ticket.
But while I try with invoking the parameterless constructor
this.kerberosRestTemplate = new KerberosRestTemplate();
And try to access to the protected resource it fails with the following error:
org.springframework.web.client.RestClientException: Error running rest call; nested exception is java.lang.IllegalArgumentException: Null name not allowed
at org.springframework.security.kerberos.client.KerberosRestTemplate.doExecute(KerberosRestTemplate.java:196)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:538)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:245)
Caused by: java.lang.IllegalArgumentException: Null name not allowed
at sun.security.krb5.PrincipalName.<init>(PrincipalName.java:356) ~[?:1.7.0_67]
at javax.security.auth.kerberos.KerberosPrincipal.<init>(KerberosPrincipal.java:123) ~[?:1.7.0_67]
at org.springframework.security.kerberos.client.KerberosRestTemplate.doExecute(KerberosRestTemplate.java:182)
What am I doing wrong here?
Please try these spring-security-kerberos. I think you are missing basic configuration which can be achieved either via xml or java configuration based .
Can also try following options:
Use loginOptions if you want to customise Krb5LoginModule options.
Use a customised httpClient.
Just call the constructor with null for keyTabLocation and any non-empty string for userPrincipal, like this:
KerberosRestTemplate restTemplate = new KerberosRestTemplate(null,"-");
Related
My Spring Boot 2.7.1 application needs to use 2 different Oauth2 webclients, that each has its own identity provider. One of them needs to go through a proxy, but not the other.
For the one going through the proxy, I build it like this :
#Bean
#Qualifier("systemA")
WebClient getWebClientForSystemA(OAuth2AuthorizedClientManager authorizedClientManager,
#Value("${asset-sync-service.systemA-proxy.host}") String proxyHost,
#Value("${asset-sync-service.systemA-proxy.port}") int proxyPort) {
var oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth.setDefaultClientRegistrationId("systemA");
var webClientBuilder=WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.apply(oauth.oauth2Configuration());
if(StringUtils.isNotEmpty(proxyHost)){
log.info("setting proxy setting ({}:{}) on webclient for systemA webclient..",proxyHost,proxyPort);
var httpClientWithSystemAProxy=HttpClient.create()
.wiretap("systemAWebClient",LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL)
.proxy(proxy -> proxy.type(Proxy.HTTP)
.host(proxyHost)
.port(proxyPort));
webClientBuilder=webClientBuilder
.clientConnector(new ReactorClientHttpConnector(httpClientWithSystemAProxy));
}
return webClientBuilder.build();
}
The first time the webClient is called and tries to get a token, it fails with :
Caused by: org.springframework.security.oauth2.core.OAuth2AuthorizationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "https://systemA.my.company/connect/oauth2/access_token": systemA.my.company; nested exception is java.net.UnknownHostException: systemA.my.company
(when I try access https://systemA.my.company/connect/oauth2/access_token in my browser, it gets resovled)
I added the wiretap in the HttpClient, because I have the feeling it's not going through the proxy, and I want to see more logs. But unfortunately, I don't see anything in my logs, despite setting Logback root logger at DEBUG level.
am I doing something wrong, either ín the wiretap config or in the config of the proxy ?
I haven't been able to fix the missing logs that I expect with wiretap, but the proxy issue is solved, thanks to
https://stackoverflow.com/a/65790535/3067542
https://blog.doubleslash.de/spring-oauth2-client-authorization-request-proxy-support/
we need to configure the proxy also in the underlying restTemplate that is used by OAuth2AuthorizedClientManager, in addition to configuring it in the webClient. Not obvious at all !
I am trying to connect to salesforce using Apache Camel salesforce component.
Here is a very simple route I am trying to start:
#Override
public void configure() throws Exception {
from("salesforce:event/Case__e")
.to("mock:end");
}
When trying to start it I am getting an obvious error saying I did not specify a client id:
Caused by: java.lang.IllegalArgumentException: clientId must be specified
at org.apache.camel.util.ObjectHelper.notNull(ObjectHelper.java:149) ~[camel-util-3.16.0.jar:3.16.0]
at org.apache.camel.component.salesforce.SalesforceLoginConfig.validate(SalesforceLoginConfig.java:238) ~[camel-salesforce-3.16.0.jar:3.16.0]
That makes perfectly sense as according to Camel docs clentId parameter must be specified. To address this I am specifying a clientId as below:
#Override
public void configure() throws Exception {
from("salesforce:event/Case__e?clientId=xyz")
.to("mock:end");
}
When trying to start the route this time I am getting a rather strange error complaining about clientId being an unknown parameter:
Failed to resolve endpoint: salesforce://event/Case__e?clientId=xyz due to: There are 1 parameters that couldn't be set on the endpoint.
Check the uri if the parameters are spelt correctly and that they are properties of the endpoint.
Unknown parameters=[{clientId=xyz}]
Not sure what I am doing wrong and how should I address this.
Thank you in advance for your inputs.
Your problem is related to the fact that clientId is a component option so it must be configured at the component level while you try to configure it like it was a query parameter / an endpoint option which cannot work.
Depending on the runtime that you use, the way to configure a component may change but the idea remains the same.
For example, assuming that you use an application.properties to configure your application, the configuration of your salesforce component would look like this:
In application.properties
# Salesforce credentials
camel.component.salesforce.login-config.client-id=<Your Client ID>
camel.component.salesforce.login-config.client-secret=<Your Client Secret>
camel.component.salesforce.login-config.refresh-token=<Your Refresh Token>
...
Here is a salesforce example https://github.com/apache/camel-examples/blob/main/examples/salesforce-consumer/
I am exposing a rest end point using Spring with a request header.
Here is the method definition:
import org.springframework.web.bind.annotation.RequestHeader;
public User createUser(#RequestHeader("system_id") String system_id, User userRequest) throws Exception
However when I use postman to send request I receive:
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public User com.java.api.createUser
Any ideas on what I am missing? Thanks!
UPDATE
When I have either the system_id or userRequest as the only parameter it works. When they are both included in the parameters they throw the error.
When using pathParameters to document the URI path parameters like below
#Test
public void documentGetRouteById() throws Exception {
this.mockMvc.perform(get("/route/{id}", "FooBar")).andExpect(status().isOk())
.andDo(document("api-getRouteById",
pathParameters(parameterWithName("id").description("die Routen ID"))));
}
I get the following excpetion
java.lang.IllegalArgumentException: urlTemplate not found. Did you use RestDocumentationRequestBuilders to build the request?
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.restdocs.request.PathParametersSnippet.extractUrlTemplate(PathParametersSnippet.java:95)
at org.springframework.restdocs.request.PathParametersSnippet.extractActualParameters(PathParametersSnippet.java:82)
at org.springframework.restdocs.request.AbstractParametersSnippet.verifyParameterDescriptors(AbstractParametersSnippet.java:77)
at org.springframework.restdocs.request.AbstractParametersSnippet.createModel(AbstractParametersSnippet.java:65)
at org.springframework.restdocs.request.PathParametersSnippet.createModel(PathParametersSnippet.java:67)
at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:64)
at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:101)
at org.springframework.test.web.servlet.MockMvc$1.andDo(MockMvc.java:158)
I am pretty sure I did the test setup like explained here.
What could I probably have done wrong?
(Spring REST docs version is 1.0.0.BUILD-SNAPSHOT)
The exception message is trying to point you in the right direction:
urlTemplate not found. Did you use RestDocumentationRequestBuilders to build the request?
You need to use RestDocumentationRequestBuilders so that Spring REST Docs can capture the URL and extract the parameters from it. This is mentioned in the documentation where it says:
To make the path parameters available for documentation, the request must be built using one of the methods on RestDocumentationRequestBuilders rather than MockMvcRequestBuilders.
Replacing your static import of MockMvcRequestBuilders.get with one for RestDocumentationRequestBuilders.get should resolve the problem.
I am using #ParamValue annotation in my controller (Spring MVC).
Say My valid URL's are:
www.temp.com/test/a,
www.temp.com/test/b and
www.temp.com/test/c
So, my RequestMapping is:
#RequestMapping(value = "/test/{value}", method = RequestMethod.GET)
Now, my problem is that if anyone types a wrong URL like this :
www.temp.com/test/youarebroken
then I have to manually handle such a case in my controller to show 404 or not found.
Isn't there something inbuilt that sends a "not found or 404" notification to server that I can use directly ?
The simplest solution is to define a custom exception handler and to throw the custom exception when a validation fails within your controller. That would require that you manage the conditions manually as you stated you do not want to do.
A different solution is to use a global exception handler and define it to deal with the HTTP errors that are handled by Spring built-in.
In this link you can see both approaches: http://www.journaldev.com/2651/spring-mvc-exception-handling-exceptionhandler-controlleradvice-handlerexceptionresolver-json-response-example
However, from your question I understand you would like to return automatically an exception when certain condition in your param value does not meet, and you do not want to validate this manually within your controller. For this, you can add custom validation for an specific class and then set #Valid before the #ParamValue.
You can check this link for DataBinding http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
And this link for specific validation on param attributes: Spring Web MVC - validate individual request params
So, in plain a solution would be to define a custom validator that throws a custom exception when fails. To set #Valid for the parameters (check link) and to adjust the custom exception to handle HTTP errors (e.g. HttpStatus.NOT_FOUND).
You can use a regex in your #RequestMapping URL. Example:
#RequestMapping(value = "/test/{value:[a-z]}", method = RequestMethod.GET)