ITfoxtec Identity SAML 2.0 - Signed LogoutRequest Failing - itfoxtec-identity-saml2

Our signed LogoutRequest is failing:
The response page contains:
Charles Sturt University.
Gateway to Charles Sturt University - Message Security Error.
The request cannot be fulfilled because the message received does not meet the security requirements of the login service.
Firefox SAML-tracer HTTP is:
GET https://idpqa.csu.edu.au/idp/profile/SAML2/Redirect/SLO?SAMLRequest=... HTTP/1.1
Host: idpqa.csu.edu.au
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://fmcentralqa.csu.edu.au/
Connection: keep-alive
Cookie: JSESSIONID=...; shib_idp_session=...; _ga=GA1.3.431747786.1588552072; monsido=31C1664470149254; _ga_09603PQVTC=GS1.1.1664587069.2.1.1664587158.0.0.0; _ga_JDV9LDRK2K=GS1.1.1664587069.2.1.1664587158.0.0.0; _ce.s=v~f561c11e21992291df080494673e8fe0dd976c1a~vpv~3; _gid=GA1.3.876195772.1664587070; lb-idp-session=...; _gat_UA-323552-1=1; cebs=1; cebsp=1; _gat_gtag_UA_323552_1=1; _gat=1
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Sec-Fetch-User: ?1
HTTP/1.1 400 400
Date: Sat, 01 Oct 2022 01:19:30 GMT
Server: Apache
Cache-Control: no-store
Content-Type: text/html;charset=utf-8
Content-Length: 1129
Connection: close
Firefox SAML-tracer Parameters is:
GET
SAMLRequest: ...
Firefox SAML-tracer SAML is:
<saml2p:LogoutRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_4dac685e-fa5b-4f14-beb5-eb3e1bbebe46"
Version="2.0"
IssueInstant="2022-10-01T01:19:30.761Z"
Destination="https://idpqa.csu.edu.au/idp/profile/SAML2/Redirect/SLO"
NotOnOrAfter="2022-10-01T01:29:30.761Z"
>
<saml2:Issuer>https://fmcentralqa.csu.edu.au/sisfm-enquiry</saml2:Issuer>
<saml2:NameID>pwijaya</saml2:NameID>
<saml2p:SessionIndex>oeft2tbnpv1u33hmtwwx42ig</saml2p:SessionIndex>
</saml2p:LogoutRequest>
Our logout.aspx page contains:
Sub SAMLLogoutSISfm()
Dim settings = ConfigurationManager.AppSettings
Dim config As Saml2Configuration = New Saml2Configuration() With
{
.AllowedIssuer = settings("SamlIdpSettings:entityid"),
.SingleSignOnDestination = New System.Uri(settings("SamlIdpSettings:loginurl")),
.SingleLogoutDestination = New System.Uri(settings("SamlIdpSettings:logouturl"))
}
'changed Core MVC AppEnvironment.MapToPhysicalFilePath to HttpContext.Current.Server.MapPath
config.SigningCertificate = ITfoxtec.Identity.Saml2.Util.CertificateUtil.Load(HttpContext.Current.Server.MapPath(settings("SamlIdpSettings:SigningCertificateFile")), settings("SamlIdpSettings:SigningCertificatePassword"), X509KeyStorageFlags.MachineKeySet Or X509KeyStorageFlags.PersistKeySet)
Dim redirectUrl As String = SamlLogoutTest(sessionIndex, nameId)
Response.write("here" + redirecturl + "<br/>")
Response.Redirect(redirectUrl)
End Sub
Function SamlLogoutTest(ByVal sessionIndex As String, ByVal nameId As String) As String
Try
Dim settings = ConfigurationManager.AppSettings
Dim binding = New Saml2RedirectBinding()
Dim config = New Saml2Configuration() With {.SignAuthnRequest = True}
Dim redirBind = binding.Bind(New Saml2LogoutRequest(config) With
{
.SessionIndex = sessionIndex,
.NameId = New System.IdentityModel.Tokens.Saml2NameIdentifier(nameId),
.Issuer = settings("SamlSpSettings:entityid"),
.Destination = New System.Uri(settings("SamlIdpSettings:logouturl"))
})
Return redirBind.RedirectLocation.ToString()
Catch ex As Exception
Return Nothing
End Try
End Function
Our web.config contains:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="SamlSpSettings:entityid" value="https://fmcentralqa.csu.edu.au/sisfm-enquiry" />
<add key="SamlIdpSettings:entityid" value="https://idpqa.csu.edu.au/idp/shibboleth" />
<add key="SamlIdpSettings:loginurl" value="https://idpqa.csu.edu.au/idp/profile/SAML2/Redirect/SSO" />
<add key="SamlIdpSettings:logouturl" value="https://idpqa.csu.edu.au/idp/profile/SAML2/Redirect/SLO" />
<add key="SamlIdpSettings:SigningCertificateFile" value="/SISfm-Enquiry/CSU/FmcentralQa3.pfx" />
<add key="SamlIdpSettings:SigningCertificatePassword" value="cadcorp" />
<!-- more -->
</appSettings>
</configuration>
How can we resolve this issue?

The logout request is default signed if a signing certificate with a private key is provided. Maybe your .NET code is not able to load the private part of the certificate.
Please take a look the ASP.NET RP sample.

Related

Missing Csrf token cookie

I'm relatively new to CakePHP (v3.7). I have an application in which I'm getting a "Missing Csrf Token Cookie" error.
In Application.php, I have:
$options = []; // I'm fine with the default options.
$csrf = new CsrfProtectionMiddleware($options);
$middlewareQueue->add($csrf);
The form page has a hidden form element with the _csrfToken in it.
I'm confused as to why it's not being found on the POST?
Digging further, I found that in CsrfProtectionMiddleware.php, the _validateToken() function below behaves as follows:
$cookies is null (there are no cookies set.)
thus, $cookie is null.
$post actually contains the content of the _csrfToken parameter from the hidden parameter on the page. However the function never looks at it. Because $cookie is null,
the if(!$cookie) statement causes an InvalidCsrfTokenException to be thrown.
protected function _validateToken(ServerRequest $request)
{
$cookies = $request->getCookieParams();
$cookie = Hash::get($cookies, $this->_config['cookieName']);
$post = Hash::get($request->getParsedBody(), $this->_config['field']);
$header = $request->getHeaderLine('X-CSRF-Token');
if (!$cookie) {
throw new InvalidCsrfTokenException(__d('cake', 'Missing CSRF token cookie'));
}
if (!Security::constantEquals($post, $cookie) && !Security::constantEquals($header, $cookie)) {
throw new InvalidCsrfTokenException(__d('cake', 'CSRF token mismatch.'));
}
}
}
Obviously, the middleware is expecting an actual cookie, in addition to a hidden parameter. Where is this cookie set (or supposed to be set?)
Update:
I checked on the browser side. The cookie is being set, but the browser isn't returning it on the POST request.
Here's CakePHP's RESPONSE to the original GET request to populate the page:
Connection: Keep-Alive
Content-Length: 3013
Content-Type: text/html; charset=UTF-8
Date: Wed, 08 May 2019 23:07:31 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.33 (Unix) PHP/7.1.1
Set-Cookie: csrfToken=b553dd2e06e57f6d514ee41a120e1c60084adafddfbaa6f72db1f7f590fcf50143876ac817d29d6f1cf9a786031d6235ba21e265b9d3b2a0ee4535854f048b66; path=/webroot/
X-Powered-By: PHP/7.1.1
Note the csrfToken cookie.
... and here's the POST that the browser sends back with the form data
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 184
Content-Type: application/x-www-form-urlencoded
DNT: 1
Host: *************
Origin: ****************
Pragma: no-cache
Referer: ***************
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
Query String Parameters
redirect: /Users/login
Form Data
_method: POST
_csrfToken: b553dd2e06e57f6d514ee41a120e1c60084adafddfbaa6f72db1f7f590fcf50143876ac817d29d6f1cf9a786031d6235ba21e265b9d3b2a0ee4535854f048b66
username: xxxxxxxxxx
password: xxxxxxxxxx
Note that it's sending back the hidden form parameter _csrfToken, but NOT the cookie.
Thanks for any help...
This turned out to be a problem with the DOCUMENT_ROOT directory setting in Apache. It was set to the parent directory of webroot, instead of to webroot itself. When I changed it everything worked.

IBM Social Business Toolkit - Create an activity

I am trying to create an activity by using IBM SBT but this does not work.
My IBM SBT version is 1.1.11.20151208-1200 (the latest).
The IBM Connections Version is 5.0 CR3.
I have had a look at the IBM example from:
IBM Documentation - Creating activities
I have the following code:
public static void testcreateData() throws ClientServicesException {
String serviceUrL = Variables.baseURL + "/activities/service/atom2/activities";
String content =
"<?xml version=\"1.0\" encoding=\"utf-8\"?> <entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:app=\"http://www.w3.org/2007/app\""
+ " xmlns:snx=\"http://www.ibm.com/xmlns/prod/sn\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\">"
+ "<title type=\"text\">New</title>"
+ "<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" term=\"activity\" label=\"Activity\"/>"
+ "<category scheme=\"http://www.ibm.com/xmlns/prod/sn/priority\" term=\"1\" label=\"Normal\"/>"
+ "<category term=\"tag1\" />" + "<category term=\"tag2\" />" + "<content type=\"html\">GoalOfActivity</content>"
+ "</entry>";
System.out.println( content );
Response res = Variables.anActivityService.createData( serviceUrL, null, content );
System.out.println( "Result: " + res.getResponse().getStatusLine().getStatusCode() );}
My XML output is the following:
<?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns:snx="http://www.ibm.com/xmlns/prod/sn" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:thr="http://purl.org/syndication/thread/1.0"><title type="text">New</title><category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="activity" label="Activity"/><category scheme="http://www.ibm.com/xmlns/prod/sn/priority" term="1" label="Normal"/><category term="tag1" /><category term="tag2" /><content type="html">GoalOfActivity</content></entry>
The error:
com.ibm.sbt.services.client.ClientServicesException: Request to url https://blabla.com/activities/service/atom2/activities returned an error response 415:Unsupported Media Type HTTP/1.1 415 Unsupported Media Type [Date: Wed, 13 Jan 2016 09:00:17 GMT, X-Frame-Options: SAMEORIGIN, Strict-Transport-Security: max-age=max-age=31536000;includeSubDomains, X-XSS-Protection: 1;mode=block, X-Permitted-Cross-Domain-Policies: master-only, X-Powered-By: Servlet/3.0, X-LConn-Auth: false, X-UA-Compatible: IE=9,8, Expires: Thu, 1 Jan 1970 00:00:00 GMT, Cache-Control: no-store, no-cache, must-revalidate, Accept: application/atom+xml, Set-Cookie: LtpaToken2=JYakBGXcJAWqNOfIc7PD5PKxpBf8spXAMh2RBtyQ/gCIFkLGuSFYLUq1Xkg335u3yLhI7lSuhNEQ4Y0j8DJB9DRr7jnQKNr8z6EwUs2Ak66eR4puAN5dvL+JiYsMj0Y9/QURoSALiLqkfWsByJpImJRRtEH8BHTaT811iaq/Cpux5h5XJ9uOPT420+4gqqzwuUyBc+71dLDs2XM/TwYx3ThTD+qA6nE42VFVszma7c4QmIrdvxASywOaFUQpCdLP63KTrs7NljOgqY82w0NNzcrz2VM3B4PUD5Fnht4HKkplB+7MBz4z1BDbwgc33BAdqNLKmd7b6vvFjAwDntIWAE7OL1rqP7k/w7rRgsqtUc1Ak074GhvkQvDjg89FeteKKG4Z7spfruNThmRWZ2IBiuQOj0cEb9LZwJMkcMrowpTWYxu0MTlcI+C9j3jV/xGK05hXvcYUmcm0HMpd0DJGE6e1J2uKEYaP7eoqjtScBtiVrGC1O1s8XXbw7vNcaUgsF0fc+3vCj0QZTJTxlNSixuRUxvRJHmTAkU7PpWMcmasTW2gQOOB6WtrST6j61865YUKSzMye8y73ps2n6+HAe87yVFNLBgm7omw+RMvCyKlhIE0go0bm2VrS2XUVMvPyT3vTo8Hlq5q1eYyzfwh2N56GhEc/H6c08Hh0K/9Mf+8=; Path=/; Domain=.blabla.com, Set-Cookie: JSESSIONID=0000MHOETW-Ow0ESyh_MllEfRId:1a17onpus; Path=/; HttpOnly, Vary: Accept-Encoding,User-Agent, Content-Length: 0, Keep-Alive: timeout=15, max=100, Connection: Keep-Alive, Content-Type: text/html, Content-Language: en-US]
I did a lot of research, but when I used code from the internet, I always got "400 Bad Request" - so I tried to focus on the IBM Documentation, but the code there does not work for me either.
Does anybody know how to do this?
Best regards

CORS - CakePHP does not accept AngularJS JSON-Request

I'm using CakePHP as backend and AngularJS as frontend, whereas front- & backend are in different domains so this is basically a CORS-situation.
Basically I'm trying to send the contents of a form to a Cake-API (later this is meant to do authentication part - but I'm failing earlier) via $http.post. So here is the code:
aeapBackend.login = function(username, password) {
return $http.post(
API_URL + 'api_mobile_user/login', {
test: username,
test2: password
}
);
};
Whereas the corresponding API in CakePHP looks like this:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array('login'));
}
public function login() {
$this->response->header(array(
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Headers' => 'Content-Type'
)
);
$this->autoRender = false;
}
What happens next is that the preflight OPTIONS request ist done - which looks quite good to me:
Request Headers:
OPTIONS /api_mobile_user/login HTTP/1.1
Host: aeap.localhost
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://asf.localhost
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://asf.localhost/?username_input=hjk&password_input=hjgk&login_button=
Accept-Encoding: gzip,deflate,sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Response headers:
HTTP/1.1 200 OK
Date: Wed, 05 Nov 2014 15:29:00 GMT
Server: Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15
X-Powered-By: PHP/5.5.15
Set-Cookie: CAKEPHP=j6st0hnq8ear2cc6psg56d6eu3; expires=Wed, 05-Nov-2014 19:29:00 GMT; Max-Age=14400; path=/; HttpOnly
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
But when the actual POST-request is done I get an status code 403:
XMLHttpRequest cannot load http://aeap.localhost/api_mobile_user/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://asf.localhost' is therefore not allowed access. The response had HTTP status code 403.
How can I avoid this? In my opinion I already enabled CORS support for Cake ['Access-Control-Allow-Origin']. It seems to me that AngularJS posts some additional informations whioch are not checked during the preflight and then rejected by the backend.
Used versions: CakePHP 2.5.3, AngularJS: 1.3.0
Thanks to Marvin Smit I was able to determine the reason for the behavior which was not connected to CORS are the headers. I set 'Access-Control-Allow-Origin' => '*'on web-server level so I was able to get a response which pointed to the security component of CakePHP.
I basically tried to send a POST-Reuqest to an API which did not expect that data should be posted to it. Therefore the access was denied. So I had to add $this->Security->csrfCheck = false to the beforeFilter:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array('login'));
$this->Security->csrfCheck = false;
}
For what it's worth, the proper way to do this for Cakephp 3 is as follows
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array('login'));
$this->eventManager()->off($this->Csrf);
}
Although, this is not recommended for AJAX requests. The following doc can help you more. CSRF And AJAX

Courtesy Redirect with NancyFx

We are battling trying to get html5mode working with AngularJs, the last hurdle is to recreate the courtesy redirect that IIS does as such:
Request
GET http://localhost/foo HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: ws7-agentry2
IIS Response
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Location: http://localhost/foo/
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Fri, 18 Jul 2014 17:09:20 GMT
Content-Length: 147
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found here</body>
The issue is that regardless of the request containing a trailing slash or not, the request object in the Nancy pipeline is identical. Since we can not differentiate between the two, we can not return a redirect without causing an infinite loop of redirects. We have tried to use url rewrites to accomplish this but to no avail, ideally I would like to get the raw url.
thanks in advance
In case anyone else needs to achieve the same results, which is to get html5mode working with IE9 & NancyFx, had to build a httpmodule as this article shows though I believe the title is wrong:
public class CourtesyRedirectModule : IHttpModule {
public void Dispose() {}
public void Init(HttpApplication context) {
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e) {
if (HttpContext.Current.Request.Url.PathAndQuery.Equals(HttpContext.Current.Request.ApplicationPath))
HttpContext.Current.Response.Redirect(HttpContext.Current.Request.ApplicationPath + "/");
}
}

CXF JAX-RS: retrieving numerous search parameters from GET request

What is the best way to retrieve numerous query parameters in a GET request with CXF / JAX-RS? Obviously having a very long list of #QueryParam annotations is not ideal. I looked at using MultiValuedMap on its own like this:
#GET
#Path("/")
public Response getProjects(MultivaluedMap<String, String> queryParams);
But this resulted in an exception being thrown, for some reason CFX attempted to handle a multipart form, so I guess MultivaluedMap is for form submission only, as documented here: http://cxf.apache.org/docs/jax-rs-data-bindings.html#JAX-RSDataBindings-Formpayloads.
What is confusing me I guess is that this is a data retrieval user case, so I mapped it to a GET service (and implemented a GET request on the client side), but on the other hand I'm submitting search parameters through a form, so what is the proper way to handle this? How do I retrieve my 20++ search parameters?
Here's a sample request:
GET http://localhost:8080/myapp-ws/services/setup/projects? brandId=&_search=false&nd=1372435138080&rows=10&page=1&sidx=projectCode&sord=desc&_=1372435 119675 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8080/myapp-ui/projects.do
Connection: keep-alive
Sample response:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Date: Fri, 28 Jun 2013 15:58:58 GMT
Content-Length: 0
Connection: close
Exception thrown from the CXF service with MultivaluedMap implementation:
Jun 28, 2013 11:58:58 AM org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: javax.ws.rs.BadRequestException: java.lang.NullPointerException
at org.apache.cxf.jaxrs.provider.FormEncodingProvider.readFrom(FormEncodingProvider.java:118)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1189)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1137)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:686)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:646)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:237)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:98)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:218)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:163)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:137)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:158)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:243)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:168)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:219)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:908)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:931)
at java.lang.Thread.run(Thread.java:773)
Caused by: java.lang.NullPointerException
at org.apache.cxf.attachment.AttachmentUtil.createAttachment(AttachmentUtil.java:294)
at org.apache.cxf.jaxrs.ext.MessageContextImpl.createAttachments(MessageContextImpl.java:252)
at org.apache.cxf.jaxrs.ext.MessageContextImpl.get(MessageContextImpl.java:75)
at org.apache.cxf.jaxrs.impl.tl.ThreadLocalMessageContext.get(ThreadLocalMessageContext.java:38)
at org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getMultipartBody(AttachmentUtils.java:56)
at org.apache.cxf.jaxrs.provider.FormEncodingProvider.readFrom(FormEncodingProvider.java:100)
... 33 more
In the end I went for a very long list of #QueryParam annotations. It's not that bad, at least it exposes a clear contract, and each parameter can be specifically documented.
You can use #BeanParam to map multiple query parameters. You can just create a bean with all parameters you want to send thru URL and add that bean in restful service with #BeanParam annotation. All your parameters gets accumulated into that bean.

Resources