Rest assured with digest auth - rest

I have a working spring-mvc application with rest services and some rest-assured tests which are fine :
#Test
public void createFoobarFromScratchReturns201(){
expect().statusCode(201).given()
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
}
=> OK
Then I implemented a digest authentication. Everything is working well, now I have to log in to use my services :
curl http://localhost:8089/foo/bar
=> HTTP ERROR 401, Full authentication is required to access this resource
curl http://localhost:8089/foo/bar --digest -u user_test:password
=> HTTP 201, CREATED
But when I try to upgrade my tests with the most obvious function, I still have a 401 error :
#Test
public void createFoobarFromScratchReturns201(){
expect().statusCode(201).given()
.auth().digest("user_test", "password") // Digest added here
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
}
=> Expected status code <201> doesn't match actual status code <401>
I found some clues with the preemptive() function, but it seems to be only implemented for basic :
// Returns an AuthenticatedScheme and stores it into the general configuration
RestAssured.authentication = preemptive().basic("user_test", "password");
// Try a similar thing, but it didn't work :
RestAssured.authentication = RestAssured.digest("user_test", "password");
Currently, I am trying to achieve two things :
I need to upgrade a couple of my tests to support digest
I need to amend the #Before of the rest of my tests suites (whose are not related to auth issues), to be already logged in.
Any ideas or documentation ?

Try enabling support for cookies in the HTTP client embedded inside Rest Assured with:
RestAssuredConfig config = new RestAssuredConfig().httpClient(new HttpClientConfig().setParam(ClientPNames.COOKIE_POLICY, CookiePolicy.BEST_MATCH));
expect().statusCode(201).given()
.auth().digest("user_test", "password") // Digest added here
.config(config)
.queryParam("foo", generateFoo())
.queryParam("bar", generateBar())
.when().post("/foo/bar/");
The HTTP client (and therefore Rest Assured) supports digest authentication and the configuration of RestAssured using the digest method works well.

Related

Disable SSL security in akka http client

I have to make https calls to an api that appears to not have validated SSL certificate. I would still like to make calls to the api using the Http().singleRequest method of akka-http.
When I make a call, I however get the following error:
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
When I make a call with curl, I get
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it.
The calls with curl however work if I had the flag --insecure.
In akka-http, I tried the following:
val badSslConfig = AkkaSSLConfig().mapSettings(
s => s.withLoose(
s.loose
.withAcceptAnyCertificate(true)
.withAllowLegacyHelloMessages(Some(true))
.withAllowUnsafeRenegotiation(Some(true))
.withAllowWeakCiphers(true)
.withAllowWeakProtocols(true)
.withDisableHostnameVerification(true)
.withDisableSNI(true)
)
)
val badCtx = Http().createClientHttpsContext(badSslConfig)
Http()
.singleRequest(
HttpRequest(
HttpMethods.POST,
uri = Uri("https://..."),
protocol = HttpProtocols.`HTTP/1.1`
),
connectionContext = badCtx
)
but I still get the same error.
What should I do to fix the issue?
PS: I understand (given the many warnings in akka-http docs) that it is something that I shouldn't do in production but I'd like this workaround to work for now...
I had similar problem some time ago and as far as I remember it had to do with this issue. Workaround for that problem is to have own implementation of SSLContext that will accept just anything. Implementation is pretty straightforward and the example can be found in the last comment of of issue linked above.

ASP double hop request in kerberos delegation scenario

Please help!
I need my asp application to request remote systems with credentials of impersonated user. But always get 401 Unauthorized errors.
I made all configurations from here: https://support.microsoft.com/en-us/help/810572/how-to-configure-an-asp-net-application-for-a-delegation-scenario
Kerberos is configured and working in my app and my test remote app(i see kerberos tickets in fiddler). Delegation, spns and everything is configured.
Thats my code usnig System.Net.Http.httpclient:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
var method = new HttpMethod("GET");
var request = new HttpRequestMessage(method, "http://testdelegationapp.avp.ru/");
var response = client.SendAsync(request).Result;
}
In fact http request is made by Apppool account (I get 401 error when restricting access to Apppool account in remote app IIS)
Here: How to get HttpClient to pass credentials along with the request?
is claimed that HttpClient cant pass security token to another thread, and its better to use synchronous methods of System.Net.WebClient
Code using webclient:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
try
{
string URI = "http://testdelegationapp.avp.ru/";
using (WebClient wc = new WebClient())
{
wc.UseDefaultCredentials = true;
string response = wc.DownloadString(URI);
}
}
finally
{
wic.Undo();
}
Result is even worse, the same 401 error, but in fiddler i can see that webclient using NTLM ticket to get to remote app!
Configuring of flowing tokens throw threads from here :Unable to authenticate to ASP.NET Web Api service with HttpClient
doesnt help either. SecurityContext.IsWindowsIdentityFlowSuppressed() is false.
WindowsIdentity.GetCurrent().Name and Thread.CurrentPrincipal.Identity.Name shows impersonated user as it should be.
All that time problem was in chrome browser, by default it prohobits kerberos delegation. You shoud add the following to registry:
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome ;
string: AuthNegotiateDelegateWhitelist ;
value: *.avp.ru
So, now my working configuration is
HttpClient for web requests.
ASP impersonation ON in IIS if you want to execute all your app under
delegated credentials. If you want method specific delegation, then use:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
wic.Undo();
HttpClient executes request in another thread , so in aspnet_config.config we need following changes:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
You can find aspnet_config.config in:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet.config

POST request succeeds on box, but fails in jenkins

I have an integration test which connects to salesforce, and gets back an authentication token.
public AuthenticationResponse getAuthenticationResponse()
{
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("client_id", consumerKey);
map.add("client_secret", consumerSecret);
map.add("grant_type", GRANT_TYPE);
map.add("username", username);
map.add("password", password);
return new RestTemplate().postForObject(LOGIN_URI, map, AuthenticationResponse.class);
}
^ That's the code the test runs.
public void testConnect(){
AuthenticationResponse response = dataDotComClient.getAuthenticationResponse();
assertNotNull(response);
assertNotNull(response.getAccess_token());
}
^ And that's the test itself.
This works fine from my, and other desktops. However, it never works in jenkins, always returning a 400 status code with no real error message behind it. Is there something I have to do in Jenkins to allow post requests to external sites?
http 400 means
Bad Request - Invalid URL"
OR
"HTTP Error 400. The request hostname is invalid."
Please make sure that your destination host is reachable from jenkins machine.
Try to login to jenkins machine and run the curl/telnet command to check the connectivity.

Spring security rest plugin: token based authentiction

I am trying to get successfully integrate Spring security rest plugin
But I am constantly failed,I am using the memcahed for token storage. Config.groovy Setup which I used to implement the plugin is :
//login end point url
grails.plugin.springsecurity.rest.login.active=true
grails.plugin.springsecurity.rest.login.endpointUrl='/api/login'
grails.plugin.springsecurity.rest.login.failureStatusCode='401'
//for memcached
grails.plugin.springsecurity.rest.token.storage.useMemcached=false
grails.plugin.springsecurity.rest.token.storage.memcached.hosts='localhost:11211'
grails.plugin.springsecurity.rest.token.storage.memcached.username=''
grails.plugin.springsecurity.rest.token.storage.memcached.password=''
grails.plugin.springsecurity.rest.token.storage.memcached.expiration=3600
//token generation
grails.plugin.springsecurity.rest.token.generation.useSecureRandom=true
grails.plugin.springsecurity.rest.token.generation.useUUID=false
I making a request on /api/login via Post man rest client with
{
"username": "john.doe",
"password": "dontTellAnybody"
}
json data but it gives me spring security auth page's html in response, Am I doing some wrong configuration?Is there any futher configuration is required.I mentioned that I am using memcache for token storage.Any Idea will be helpfull for me.
Edit: please see the logs file
Edit2 : please check this log file

Spring Security authenticating RESTful web service

I'm working on adding basic authentication to my RESTful web service (implemented using Spring MVC) with Spring Security having never really used it before. Right now I'm simply using an in-memory UserService with the intention of adding a repository-based one later.
<security:http>
<security:http-basic />
<security:intercept-url pattern="/**" access="ROLE_ADMIN" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="admin"
authorities="ROLE_USER, ROLE_ADMIN" />
<security:user name="guest" password="guest"
authorities="ROLE_GUEST" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
This works fine, i.e. sending the following request grants me access to the desired resource (where the encoded string is admin:admin):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic YWRtaW46YWRtaW4=
And sending the following request gives me an Error 403 (where the encoded string is guest:guest):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
However, sending a request where the provided username is not contained in the UserService does not result in an Error 403 as I expected (or at least desired) but instead continues prompting for a username and password. E.g. (where the encoded string is user:user):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic dXNlcjp1c2Vy
Is there additional configuration required to respond with an Error 403 when unrecognized user credentials are provided? How can I go about doing that?
Firstly,
403 Forbidden should be used when user is already authenticated but is not authorized to perform particular action. In your example guest is successfully authenticated but is not granted permission to see page because he is just a guest.
You should use 401 Unauthorized to indicate that your user was not authenticated successfully.
More on HTTP errors codes: http://en.wikipedia.org/wiki/HTTP_401#4xx_Client_Error
Secondly,
you can specify your custom behavior by extending BasicAuthenticationFilter.
There is protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse AuthenticationException failed) method that you can override and do whatever is adequate. In default implementation that method is empty.
Spring Security docs on injecting custom filter: CLICK
Edit:
What Spring Security does each time your authentication input is invalid:
public class BasicAuthenticationEntryPoint implements AuthenticationEntryPoint {
...
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\"");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
So, the default behavior is correct. User is sent 401 and is asked to provide valid login/credentials.
Before overriding, try to understand the default behavior. Source code: CLICK
You should try this in a client like wget or curl. You browser nags you several times for Basic redentials if your are rejected with 401. This is probably the case here.