How to secure restful webservice without using authentication - web-services

Can some one please let me know what are all the ways to secure restful web service written in spring boot project using spring rest(there is no user credentials check as this service is invoked by remote application sitting on different server)
Problem Statement:
I have a rest class and a method, which should be accessed by another remote application. Remote application will not send anything except body content and content-type. In this scenario how can I secure this rest service so that service can be accessible by only that particular remote application.
#RequestMapping("/rest")
#RestController
public class WorkflowController {
#RequestMapping(value = "ticket/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public Long startWorkflow(#RequestBody TicketInfo ticketInfo) {
...//DO SOMETHING
Long id = 1L;
return id; // return some long value
}
}
Please suggest what is the way to achieve this.
Thanks in advance

Ok so i dont know if i completely understand your question, but ill asume different scenarios.
Say your client application sits on a
static ip you could create a filter and a whitelist of ip addresses, that would be really simple, and probably not good enough.
If thats not the case you can use a parameter either GET or POST and again create a filter, you'll have to send the authentication string in your first call to get authentication. you'll also have to implement the authentication manager.
if(hsr.getParameter("ex_code") != null){
String exCode= hsr.getParameter("ex_code");
String userToken = new String( Base64.getDecoder().decode(hsr.getParameter("ex_code")));
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(serviceThatReturnsAUserDetailsFacade.loadUserByUsername(userToken),
exCode);
token.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
try {
authentication = authenticationManager.authenticate(token);
....

If you do not want to implement any security & just would like to validate the host & port (only one app can run on a particular host & port) and assuming you using Spring then you can simply fetch following from incoming HttpServletRequest :-
a) RemoteAddr -> IP address of machine from which request originated.
b) RemoteHost -> Host name of machine from which request originated.
c) RemotePort -> Port of machine from which request originated.
Have one interfacing method in place which will validate this & if valid then allow it to go through while if invalid then return respective error msg to client.
Apart from this there is one other option also known as "Anonymous Authorization" with details here.

Related

How to attach X509Certificate2 to webservice (Apple GSX / C# specific)

Apple released their New Generation WSDL on the 15 of August this year (2015) and the big change was that every call to the WSDL had to be validated with a certificate file.
I've done the process to get the certificate from Apple, and I've whitelisted our server IP, and I've even verified that I can get access to the service endpoint from our server by coding a simple interface using HttpWebRequest where I easily can attach the certificate using webRequest.ClientCertificates.Add(), so I know everything is ready for it to work.
But, my problem arises when I download the WSDL from https://gsxwsut.apple.com/apidocs/prod/html/WSArtifacts.html?user=asp
I import the WSDL into Visual Studio and when I try to make an instance of the client class, the only one I find is GsxWSEmeaAspPortClient, which seems to be correct as it has all the functions for authenticate and various tools, but it does not have ClientCertificates. It does have ClientCredentials which have ClientCertificate, but when I try to set the cert there, it's as tho it's never set.
I'm guessing the service code transmits the data via either HttpWebRequest or WebRequest, so if I just can get to the request code from my instance of the class (GsxWSEmeaAspPortClient) I can probably fix it, but I can't seem to get there.
I've looked at this question: How can I connect with Apple's GSX NewGeneration webservices with WCF? which suggests it really should be that easy, but I don't have the GsxWSEmeaAspService, only the GsxWSEmeaAspPortClient from my Visual Studio's generation of the WSDL.
If anyone has any ideas which can point me in any direction towards victory I'd be eternally grateful.
I'm using Visual Studio 2013 and the solution is .Net v4.5.1 if that makes any difference.
I've pasted new code here:
public void Authenticate() {
// Use custom binding with certificate authentication
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// Create service endpoint
// Use proper endpoint address - eg. gsxapi.apple.com for production
EndpointAddress endpoint = new EndpointAddress("https://gsxapiit.apple.com/gsx-ws/services/emea/asp");
// Create new service
Apple.GsxWSEmeaAspPortClient service = new Apple.GsxWSEmeaAspPortClient(binding, endpoint);
// Set loaded certificate
service.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(
"[PathToContainerFromStep7].p12",
"[YourPasswordFromStep8]");
// Create authenticate request object
Apple.authenticateRequestType auth = new Apple.authenticateRequestType()
{
languageCode = "en",
userId = "[YourAppleServiceAccountNumber]",
userTimeZone = "[YourTimeZone]",
serviceAccountNo = "[YourSoldToNumber]"
};
// Authenticate to Apple GSX
Apple.authenticateResponseType session = service.Authenticate(auth);
// Assign your new session id object
userSessionId = new Apple.gsxUserSessionType() { userSessionId = session.userSessionId };
}

RESTEasy Client Proxy Preemptive Basic Authentication

I am using RESTEasy Proxy Framework to call my Rest-Services. I would like to use preemptive authentication with the proxy framework.
Thats my current Code:
public void callSomeService() throws Exception {
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
DefaultHttpClient client = new DefaultHttpClient();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
USERNAME, PASSWORD);
AuthScope authscope = new AuthScope(AuthScope.ANY_HOST,
AuthScope.ANY_PORT, AuthScope.ANY_REALM);
client.getCredentialsProvider().setCredentials(authscope, credentials);
ApacheHttpClient4Executor executer = new ApacheHttpClient4Executor(client);
dummyResource = ProxyFactory.create(DummyResource.class,
"http://localhost:8888/myapp/rest/", executer);
// Do some calls here
}
When I monitor the traffic of my application, the Rest-Service gets called twice:
First the client receives an 401 Error (UNAUTHORIZED)
In the second request there is the Authorization Header added and everything works
fine.
What I actually want to do is that the Authorization Header is already added in the first request! How can I do that?
I am using RESTEasy 2.3.5! I also read the documentation (http://docs.jboss.org/resteasy/docs/2.3.5.Final/userguide/html_single/index.html#transport_layer) where is an example given for preemptive authentication, which actually doesnt work, because of this code:
BasicScheme basicAuth = new BasicScheme();
authCache.put("com.bluemonkeydiamond.sippycups", basicAuth);
You're right, the example in the documentation does not compile. Try replacing the string "com.bluemonkeydiamond.sippycups" with an instance of HttpHost. The HttpHost class has several constructors so be sure to look at the JavaDocs. The simplest constructor takes a string. For example,
BasicScheme basicAuth = new BasicScheme();
authCache.put(new HttpHost("com.bluemonkeydiamond.sippycups"), basicAuth);

How do I capture (in Fiddler) the HTTP requests issued by Nancy.Testing.Browser

I have the following NancyFX unit test.
var browser = new Browser(new UnitTestBootstrapper());
var response = browser.Post("/login", with =>
{
with.FormValue("UserName", userName);
with.FormValue("Password", password);
});
response.ShouldHaveRedirectedTo("/home");
You can see that I use an instance of Nancy.Testing.Browser to POST some form values. I would like to capture this Http request in Fiddler but I am not sure how to set-up the Browser (a proxy perhaps?)
Thanks
You can't because they never hit the network; that's the whole point of the browser class - to give you end to end testing without the performance hit/configuration issues of having to use hosting/http/networking/browser rendering.
If you want to go via the networking stack then use something like Selenium, or spin up a self host and poke it with EasyHttp or manually with HttpClient.

WebRequest.DefaultWebProxy.Credentials is null and WCF service call fails if I'm behind proxy

I'm behind ISA Server Proxy and I need to call a web service. Given its wsdl I've created proxies (using Add Service Reference command) and have tried to call the service, but it raised an exception telling me that proxy authorization is required. After some research I've found a solution to my problem
var webproxy = new WebProxy(new Uri("http://<address>:<port>").ToString(), true, new string[]
{
})
{
Credentials = networkCredentials,
BypassProxyOnLocal = false
};
WebRequest.DefaultWebProxy = webproxy;
After this piece of code I'm able to call web service. But as I've read here by default DefaultWebProxy uses the same settings as set in IE. However WebRequest.DefaultWebProxy.Credentials is null and I'm unable to pass thru the proxy. Why?
I've was also same boat. The last answer on this post helped me.
How do I determine (elegantly) if proxy authentication is required in C# winforms app
Especially.
//HACK: add proxy
IWebProxy proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
req.Proxy = proxy;
req.PreAuthenticate = true;
//HACK: end add proxy

Sending Cookies over WCF using the ChannelFactory

I use an IOC container which provides me with IService.
In the case where IService is a WCF service it is provided by a channel factory
When IService lives on the same machine it is able to access the same cookies and so no problem however once a WCF Service is called it needs to be sent those cookies.
I've spent a lot of time trying to find a way to send cookies using a channel factory and the only way I could find that works is the following
var cookie = _authenticationClient.GetHttpCookie();
HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers.Add(HttpRequestHeader.Cookie, cookie.Name + "=" + cookie.Value);
using(var scope = new OperationContextScope((IClientChannel)_service))
{
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
var result = _service.Add(details);
if (result.Result == RPGResult.Success)
{
return RedirectToAction("Index", "Home", result.Id);
}
}
The problem with me using that method is that I have to know that I'm calling a WCF Service which is not always the case. I've tried writing a wrapper for the ChannelFactory that opens a new operationcontextscope when it creates a new service and various other solutions but nothing has worked.
Anyone have any experience with sending cookies over WCF Services?
I found a solution involving using SilverLight, unfortunately I'm not using silverlight, the solution is here: http://greenicicleblog.com/2009/10/27/using-the-silverlight-httpclient-in-wcf-and-still-passing-cookies/
Unfortunately standard .net doesn't contain the IHttpCookieContainerManager interface
Ideally I would be able to use something similar,i.e. I would be able to tell the channelfactory to pass a cookie whenever it opened.
If anyone has a better way to pass a token that is used for authentication that would be appreciated too.
I have a solution where I create a proxy class of IService and then every time a method on IService is called it invokes the proxy created by the channel factory but the call itself is wrapped in an operationcontextscope just like the one I have in my question.
I used the proxy factory from this link http://www.codeproject.com/KB/cs/dynamicproxy.aspx