MockMVC test throws io.jsonwebtoken.MalformedJwtException when reading JSON - spring-security

I am using MockMVC to test the JWT Token/authentication and I am having some trouble understanding why the JSON cannot be read.
This is the test that Ive written:
#SpringBootTest
#AutoConfigureMockMvc
public class JwtSecurityTest {
#Autowired
private MockMvc mockMvc;
#Test
public void existentUserCanGetTokenAndAuthentication() throws Exception {
String username = "user";
String password = "pass";
String body = "{"username":"" + username + "","password":"" + password + ""}";
MvcResult result = mockMvc.perform(post("http://localhost:8080/login/authenticate")
.contentType(MediaType.APPLICATION_JSON)
.content(body))
.andDo(MockMvcResultHandlers.print())
.andReturn();
String token = result.getResponse().getContentAsString();
mockMvc.perform(MockMvcRequestBuilders.get("http://localhost:8080/kund")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk());
}
And the error I get is:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = application/json
Body = {"jwt":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzbHkiLCJleHAiOjE2NTMwODM5NDMsImlhdCI6MTY1MzA0Nzk0M30.V5qqIRzlAtkXEK_OcFbiIlEaOdej3oyGFMy6Aw57ZB8"}
Forwarded URL = null
Redirected URL = null
Cookies = []
io.jsonwebtoken.MalformedJwtException: Unable to read JSON value: ?^?[????M
I find it weird because in the body, we can clearly see that the token looks good.

Related

rest assured File not Found error

When i use authorization in headers for rest assured by bassing token variable giving "File Not Found" error. And if hardcode the token in headers then it's working successfully. Can anyone help me out what can be the issue. Below is my code,
public static void getIndentId() throws IOException {
if(indentId == null){
Payloads pal = new Payloads();
RestAssured.baseURI = CommonFunctions.getSitApiGatewayEndPoint();
String sessionKey = GbPortalLogin.getSessionKey();
String token = "Token "+sessionKey;
System.out.println(token);
Response res = given().
header("Content-Type","application/json").
header("Authorization",token).
body(pal.createIndentPayload()).
when().post(Resources.createNbIndent).
then().extract().response();
String s = res.asString();
System.out.println(s);
/*System.out.println(res.getBody().toString());
JsonPath js = CommonFunctions.rawToJson(res);
indentId = js.get("id").toString();*/
}

Jenkins Docker container - 403 no valid crumb was included in the request

I'm setting up my Jenkins server, and on simple requests in the web interface, like creating a folder, a pipeline, a job, etc., I periodically get the following error:
HTTP ERROR 403
Problem accessing /job/Mgmt/createItem. Reason:
No valid crumb was included in the request
The server is using the Jenkins/Jenkins container, orchestrated by Kubernetes on a cluster on AWS created with kops. It sits behind a class ELB.
Why might I be experiencing this? I thought the crumb was to combat certain CSRF requests, but all I'm doing is using the Jenkins web interface.
Enabling proxy compatibility may help to solve this issue.
Go to Settings -> Security -> Enable proxy compatibility in CSRF Protection section
Some HTTP proxies filter out information that the default crumb issuer uses to calculate the nonce value. If an HTTP proxy sits between your browser client and your Jenkins server and you receive a 403 response when submitting a form to Jenkins, checking this option may help. Using this option makes the nonce value easier to forge.
After a couple of hours of struggling, I was able to make it work with curl:
export JENKINS_URL=http://localhost
export JENKINS_USER=user
export JENKINS_TOKEN=mytoken
export COOKIE_JAR=/tmp/cookies
JENKINS_CRUMB=$(curl --silent --cookie-jar $COOKIE_JAR $JENKINS_URL'/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' -u $JENKINS_USER:$JENKINS_TOKEN)
echo $JENKINS_CRUMB
curl --cookie $COOKIE_JAR $JENKINS_URL/createItem?name=yourJob --data-binary #jenkins/config.xml -H $JENKINS_CRUMB -H "Content-Type:text/xml" -u $JENKINS_USER:$JENKINS_TOKEN -v
when calling the http://JENKINS_SERVER:JENKINS_PORT/JENKINS_PREFIX/crumbIssuer/api/json you receive a header ("Set-Cookie") to set a JSESSIONID, so you must supply it in the upcoming requests you issue,
the reason is that jenkins test for valid crumb in this manner: comparing the crumb you send in the request with a crumb it generates on the server side (using your session id),
you can see it in jenkins code: scroll down to method:
public boolean validateCrumb(ServletRequest request, String salt, String crumb)
it means you HAVE to include a session in the next requests (after fetching the crumb)!
so the curl --cookie must be used as ThiagoAlves stated in his solution
i use java so i used this next tester (HTTPClient would be prefered, but i wanted a simple java only example):
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;
public class JobRunner
{
String jenkinsUser = "tester";
String jenkinsPassword = "1234"; // password or API token
String jenkinsServer = "localhost";
String jenkinsPort = "8080";
String jenkinsPrefix = "/jenkins";
String jSession = null;
String crumb = null;
HttpURLConnection connection = null;
String responseBody = "";
public void openConnection(String requestMethod, String relativeURL) throws Exception
{
// prepare the authentication string
String authenticationString = jenkinsUser + ":" + jenkinsPassword;
String encodedAuthenticationString = Base64.getEncoder().encodeToString(authenticationString.getBytes("utf-8"));
// construct the url and open a connection to it
URL url = new URL("http://" + jenkinsServer + ":" + jenkinsPort + jenkinsPrefix + relativeURL);
connection = (HttpURLConnection) url.openConnection();
// set the login info as a http header
connection.setRequestProperty("Authorization", "Basic " + encodedAuthenticationString);
// set the request method
connection.setRequestMethod(requestMethod);
}
public void readResponse() throws Exception
{
// get response body and set it in the body member
int responseCode = connection.getResponseCode();
switch (responseCode)
{
case 401:
System.out.println("server returned 401 response code - make sure your user/password are correct");
break;
case 404:
System.out.println("server returned 404 response code - make sure your url is correct");
break;
case 201:
case 200:
System.out.println("server returned " + responseCode + " response code");
InputStream responseBodyContent = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseBodyContent));
String currentLine;
while ((currentLine = bufferedReader.readLine()) != null)
{
responseBody = responseBody + currentLine + "\n";
}
break;
default:
System.out.println("server returned error response code: " + responseCode);
break;
}
}
public void setSessionCookie() throws Exception
{
jSession = connection.getHeaderField("Set-Cookie");
System.out.println("jSession: " + jSession);
}
public void disconnect() throws Exception
{
if(connection!=null)
{
connection.disconnect();
connection = null;
responseBody = "";
}
}
public void getCrumb() throws Exception
{
try
{
openConnection("GET", "/crumbIssuer/api/json");
readResponse();
setSessionCookie();
int crumbIndex = responseBody.indexOf("crumb\":\"");
if(crumbIndex!=-1)
{
int crumbIndexEnd = responseBody.indexOf("\",\"", crumbIndex);
crumb = responseBody.substring(crumbIndex + "crumb\":\"".length(), crumbIndexEnd);
System.out.println(crumb);
}
}
finally
{
disconnect();
}
}
public void runJob() throws Exception
{
try
{
openConnection("POST", "/job/test/build");
connection.setDoOutput(true);
connection.setRequestProperty("Cookie", jSession);
connection.setRequestProperty("Jenkins-Crumb", crumb);
readResponse();
System.out.println("Post response: " + responseBody);
}
finally
{
disconnect();
}
}
public static void main(String[] args)
{
JobRunner jobRunner = new JobRunner();
try
{
jobRunner.getCrumb();
jobRunner.runJob();
}
catch (Exception err)
{
err.printStackTrace();
}
}
}

Spring to Ping: how to configure Spring Rest Service to use External Authorization Server PingFederate

Does anyone know how to configure a Spring Rest Service to use PingFederate as an External Authorization Server?
Asked this question before, it was closed for god knows why. But here is the answer that I found. I based this on a demo that uses Google as an external authorization server. The problem with the usual demos is that they all use the Spring Authorization Server. Here is the place to start https://arnoldgalovics.com/google-oauth-with-spring-security-as-separated-resource-server/ Then modify the GoogleAccessTokenValidator like this (below). Questions, fire away...
private HttpHeaders createHeaders(final String username, final String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
set( "Authorization", authHeader );
}};
}
#SuppressWarnings("unchecked")
private Map<String, ?> getPingResponse(String accessToken) {
//Ping speaks text/html
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof StringHttpMessageConverter) {
StringHttpMessageConverter stringConverter = (StringHttpMessageConverter) converter;
stringConverter.setSupportedMediaTypes(ImmutableList.of(new MediaType("text", "html", StringHttpMessageConverter.DEFAULT_CHARSET)));
}
}
//URL
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(checkTokenUrl)
.queryParam("grant_type", "urn:pingidentity.com:oauth2:grant_type:validate_bearer")
.queryParam("token", accessToken);
String url = builder.build().encode().toUri().toString();
//Basic Auth (from Ping, OAuth Settings, Manage Clients
HttpEntity<Object> requestEntity = new HttpEntity<Object>(createHeaders("my-trusted-client", "secret"));
//unused Spring exchange variables
Map<String, String> variables = ImmutableMap.of("ping does not", "use this"); //token only in queryParam above
//validation call to Ping
Map map = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class, variables).getBody();
return (Map<String, Object>) map;
}
I tried this using jose4j library
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.7.6</version>
</dependency>
Now, following is the code which validates the JWT and get claims.
String jwtToken = "<token>"
HttpsJwks httpsJkws = new HttpsJwks("<Ping Server Public cert URL>");
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
.setRequireExpirationTime()
.setAllowedClockSkewInSeconds(30)
.setRequireSubject()
.setExpectedIssuer("<Issuer URL>")
.setExpectedAudience("<audience>")
.setVerificationKeyResolver(httpsJwksKeyResolver)
.setJwsAlgorithmConstraints(
AlgorithmConstraints.ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256)
.build();
try
{
JwtClaims jwtClaims = jwtConsumer.processToClaims(jwtToken);
} catch (InvalidJwtException e) {
System.out.println("Invalid JWT! " + e);
if (e.hasExpired())
{
System.out.println("JWT expired at " + e.getJwtContext().getJwtClaims().getExpirationTime());
}
if (e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID))
{
System.out.println("JWT had wrong audience: " + e.getJwtContext().getJwtClaims().getAudience());
}
}
We can integrate above code via SpringBoot interceptor by extracting the JWT token received in HTTP header.

dotnetopenauth twitter api 1.1 signed request

I stuсk on using DNOA library for twitter 1.1 api
enter code here
I am trying to call users/show.json api
protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response)
{
string accessToken = response.AccessToken;
string str2 = response.ExtraData["user_id"];
string userName = response.ExtraData["screen_name"];
Uri location = new Uri("https://api.twitter.com/1.1/users/show.json?user_id=" + str2);
MessageReceivingEndpoint profileEndpoint = new MessageReceivingEndpoint(location, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
HttpWebRequest request = base.WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken);
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("accesstoken", accessToken);
try
{
using (WebResponse wresponse = request.GetResponse())
{
var str = Utilities.ProcessResponse(wresponse);
var json = JObject.Parse(str);
dictionary.AddNotEmpty("name", json.Value<string>("name"));
dictionary.AddNotEmpty("location", json.Value<string>("location"));
dictionary.AddNotEmpty("description", json.Value<string>("description"));
dictionary.AddNotEmpty("url", json.Value<string>("url"));
}
}
catch (Exception)
{
}
return new AuthenticationResult(true, base.ProviderName, str2, userName, dictionary);
}
This what is sends to twitter
GET https://api.twitter.com/1.1/users/show.json?user_id=2193937074 HTTP/1.1
Authorization: OAuth oauth_token="2193937074-cgmZbmJIIb75f7MkQgbdjuvQaen2xzM1WFXXC7G",oauth_consumer_key="XVCgN3fkwzTGgeSm1FBa1Q",oauth_nonce="93UjjRkP",oauth_signature_method="HMAC-SHA1",oauth_signature="YzfXzU3VeEI9xl2SfuknPB33%2FiM%3D",oauth_version="1.0",oauth_timestamp="1389265955"
Host: api.twitter.com
The responce is
HTTP/1.1 401 Unauthorized
content-length: 63
content-type: application/json; charset=utf-8
date: Thu, 09 Jan 2014 11:12:36 UTC
server: tfe
set-cookie: guest_id=v1%3A138926595613849064; Domain=.twitter.com; Path=/; Expires=Sat, 09-Jan-2016 11:12:36 UTC
strict-transport-security: max-age=631138519
{"errors":[{"message":"Could not authenticate you","code":32}]}
The dev.twitter's OAuth tool shows the valid sample of signed header:
GET https://api.twitter.com/1.1/users/show.json?user_id=2193937074 HTTP/1.1
Authorization: OAuth oauth_consumer_key="XVCgN3fkwzTGgeSm1FBa1Q", oauth_nonce="dbf6f6c1aa6dc226de25265da3d63167", oauth_signature="K3Qfyc9qANFgckQNyqsaDWCnh%2BY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1389266681", oauth_token="2193937074-cgmZbmJIIb75f7MkQgbdjuvQaen2xzM1WFXXC7G", oauth_version="1.0"
Host: api.twitter.com
It loook's like the main difference is in length of the oauth_nonce?
DNOA - oauth_nonce="93UjjRkP"
OAuth tool - oauth_nonce="dbf6f6c1aa6dc226de25265da3d63167"
I solved the problem.
The main problem is how the signature is created, the TokenSecret is excluded from it's forming. The core of the this behavior is the AuthenticationOnlyCookieOAuthTokenManager manager that is used inside the base DotNetOpenAuth.AspNet.Clients.TwitterClient class.
public class AuthenticationOnlyCookieOAuthTokenManager : IOAuthTokenManager
{
...
public virtual void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret)
{
HttpCookie cookie = new HttpCookie("OAuthTokenSecret") {
Value = string.Empty, //<<< now it's empty
Expires = DateTime.UtcNow.AddDays(-5.0)
};
this.Context.Response.Cookies.Set(cookie);
}
...
}
It's just remove the tokenSecret;
The solution is to use the DotNetOpenAuth.AspNet.Clients.InMemoryOAuthTokenManager class. So you need just derive from OAuthClient and implement proper constructor:
public class TwitterClient : DotNetOpenAuth.AspNet.Clients.OAuthClient
{
protected TwitterClient(string appKey, string appSecret) :
base ("twitter",
new DotNetOpenAuthWebConsumer(
TwitterServiceDescription,
new InMemoryOAuthTokenManager(appKey, appSecret)))
{ }
...
}
Also have found the familiar post Custom OAuth client in MVC4 / DotNetOpenAuth - missing access token secret

Connecting to Twitter - RestSharp OAuth2

I am attempting to connect to the Twitter API with these instructions
https://dev.twitter.com/docs/auth/application-only-auth
Here is my code:
var baseUrl = "http://api.twitter.com/";
var client = new RestClient(baseUrl);
var request = new RestRequest("/oauth2/token", Method.POST);
var concat = ConfigurationManager.AppSettings["TwitterConsumerKey"] + ":" +
ConfigurationManager.AppSettings["TwitterConsumerSecret"];
string encodeTo64 = concat.EncodeTo64();
request.AddHeader("Authorization", "Basic " + encodeTo64);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
request.AddBody("grant_type=client_credentials");
IRestResponse restResponse = client.Execute(request);
EncodeTo64
static public string EncodeTo64(this string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
Response.Content is the following
"{\"errors\":[{\"code\":170,\"label\":\"forbidden_missing_parameter\",\"message\":\"Missing required parameter: grant_type\"}]}"
Is this part wrong?
request.AddBody("grant_type=client_credentials");
I have verified that my credentials are correct (I got that error before, but resolved it, so it should be OK).
The instructions on the Twitter page confused me. "The body of the request must be grant_type=client_credentials."
As for Restsharp, it's not AddBody, but AddParameter.
So:
request.AddParameter("grant_type", "client_credentials");

Resources