RestAssured testing, get user token - spring

What I want to do: I want to test my endpoint using RestAssured. The key is that the endpoint is available only for users who are logged in. For logging in I'm using spring security default endpoint with custom successHandler in which I'm setting some random token, saving it to database and returning in header "User-Token". I'm not creating a session on the back end. When I want to access a secured endpoint, front-end makes a call to it, with "User-Token" header. Then I'm using the token for checking in the database. Each token is different and random. Also I don't use any spring-security things for token. Now I want to test this behavior.
Technologies: React & Redux, Spring Boot, RestAssured, JUnit, Tomcat
What's not working: First of all, I'm not really sure how to obtain the token. I mean I can force it by hand to database to some test user, but AFAIK it's a bad bad practice. I read the documentation and come across part about auth().form. But below it was mentioned that it's not the best approach as have to made to the server in order to retrieve the webpage with the login details and it's not possible - webpage is totally separated from backend. I did try the approach nevertheless but it didn't work.
#Before
public void LogInUser(){
String loginUrl = "http://localhost:8080/login";
userToken =
given().auth().form("username","password").
when().get(loginUrl).getHeader("User-Token");
System.out.println(userToken);
}
So then I thought that maybe I don't need auth() at all - I don't need session, so calling the endpoint itself with data should be enough. I checked how data is passed from front-end to back-end and did this:
Form Data: username=something&password=something
#Before
public void LogInUser(){
String loginUrl = "http://localhost:8080/login";
userToken =
given().parameter("username=oliwka&password=jakies")
.when().get(loginUrl).getHeader("User-Token");
System.out.println(userToken);
}
And while it's passing, userToken is null. It's declared as class variable not method variable and it's String.
How can I obtain token for user and test my endpoint for which I need a token?

You can use below procedure to get the access token.
Step 1 : Create a method that will accept a json string and parse the data and return the access token. below is the method. You can use your preferable json parser library.
public String getAccessToken(String jsonStr) {
JSONParser parser = new JSONParser();
Object obj = null;
try {
obj = parser.parse(jsonStr);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JSONObject jsonObject = (JSONObject) obj;
String accessToken = (String) jsonObject.get("access_token");
System.out.println("access_token : " + accessToken);
return accessToken;
}
Step 2 : Now call your login api with username and password like below
String loginUrl = "http://localhost:8080/login";
Response res = null;
String returnValue = "";
response = given().param("username", "yourUserName")
.param("password", "yourpassword")
.param("client_id", "If Any otherwise skip it")
.param("grant_type", "If Any otherwise skip it")
.param("clear_all", "true")
.post(loginUrl);
returnValue = response.body().asString();
String accessToken = getAccessToken(returnValue);
Please let me know if you can get your desired access token.

Related

Spring Boot session attribute is null in REST controller

I am developing a social Twitter app for which I am using Spring Boot 2.2.2. I am following the instructions here https://careydevelopment.us/2017/05/24/implement-twitter-login-solution-spring-boot/.
I have just modified my code to be more REST oriented instead of RedirectView(as done in above link)
#PostMapping("/getToken")
public ResponseEntity<TwitterTokenResponse> getToken(HttpServletRequest request) throws Exception {
Twitter twitter = getTwitter();
String callbackUrl = "http://localhost:3000/settings";
RequestToken requestToken = twitter.getOAuthRequestToken(callbackUrl);
request.getSession().setAttribute("requestToken", requestToken);
*//setting twitter attribute in session*
request.getSession().setAttribute("twitter", twitter);
String twitterUrl = requestToken.getAuthorizationURL();
TwitterTokenResponse twitterTokenResponse = new TwitterTokenResponse(requestToken.getToken(), requestToken.getTokenSecret(), true, 0L, null);
log.info("Authorization url is " + twitterUrl);
log.info("Request token is " + requestToken);
return ResponseEntity.ok(twitterTokenResponse);
}
#PostMapping("/twitterCallback")
public ResponseEntity<TwitterTokenResponse> twitterCallback(#RequestParam(value = "oauth_verifier", required = false) String oauthVerifier, #RequestParam(value = "denied", required = false) String denied, HttpServletRequest request) throws Exception {
if (denied != null) {
log.error("Could not get token from Twitter! Access denied");
return null;
}
*//Getting twitter attribute back from session but it is null*
Twitter twitter = (Twitter) request.getSession().getAttribute("twitter");
RequestToken requestToken = (RequestToken) request.getSession().getAttribute("requestToken");
AccessToken token = twitter.getOAuthAccessToken(requestToken, oauthVerifier);
request.getSession().removeAttribute("requestToken");
TwitterTokenResponse twitterTokenResponse = new TwitterTokenResponse(token.getToken(), token.getTokenSecret(), true, token.getUserId(), token.getScreenName());
log.info("Access token is " + token);
return ResponseEntity.ok(twitterTokenResponse);
}
As can be seen in getToken() method I am setting the twitter variable in session and trying to get the same variable from session in twitterCallback() method. the twitter attribute I am getting from the session is always coming null. Any reasons why it is like that and what can be done to solve this?
Thank you
First - please check your sessionid in both controller methods, they must be the same. If they are not, so obviously you have a new session that means there is no "twitter" attribute on it.
Second - There may be a time period between your requests (between the first request to get token and second to fetch it), that can cause the session to kill and generate a new one that doesn't have "twitter" attribute anymore, So Please check your session timeout also.

Oauth2 Spring Security Resource Server and Independent Auth Server

everyone!
I'm new to Oauth2 and I've had different approaches with it.
I have a doubt. I'm actually building a Provider Server with Spring Security and I have an external access token provider (Google and AWS Cognito).
I know the process to get the access token following the code grant flow (Which is the one I want to implement). I built an Android app that gets the code and changes it for the access token.
My question is:
How do I validate that the token I'm sending to the Provider Server is a valid one using Spring Security to also access the protected resources that the server has?
Thank you in advance.
I think there are two alternatives either u get the public key and verify the token urself or maybe they have an endpoint where you can send the token and know if its a valid one or not.
Something like this
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList(CLIENT_ID))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
} else {
System.out.println("Invalid ID token.");
}
Link: https://developers.google.com/identity/sign-in/web/backend-auth

Web API authentication - returning the same OAUTH refresh token

I am pretty new to this.. so any help would be greatly appreciated.
I have a WebApi service that uses OAUTH token and refresh token authentication.
All works well at the moment:
step1: I send in the user and password and it generates an authentication token and a refresh token. The refresh token is saved in the DB.
step2. I can now use the refresh token and i receive the authentication token and a new refresh token. I want a way to use the same refresh token i sent and not reuse a new one.
This is my code for the refresh token:
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
RefreshTokensRepository _repo = new RefreshTokensRepository();
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
//HERE I regenerate the token, but I have no idea how to retrieve the already sent one.
var refreshTokenId = Guid.NewGuid().ToString("n");
//saving in BD:
var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
var token = new RefreshTokens()
{
Id = Helper.GetHash(refreshTokenId),
ClientId = clientid,
Subject = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
context.Ticket.Properties.IssuedUtc = DateTime.UtcNow;
context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime));
token.ProtectedTicket = context.SerializeTicket();
var result = _repo.Add(token);
if(!string.IsNullOrEmpty(result))
context.SetToken(refreshTokenId);
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
string hashedTokenId = Helper.GetHash(context.Token);
RefreshTokensRepository _repo = new RefreshTokensRepository();
var refreshToken = _repo.FindById(hashedTokenId);
if (refreshToken != null)
{
//Get protectedTicket from refreshToken class
context.DeserializeTicket(refreshToken.ProtectedTicket);
_repo.Remove(hashedTokenId);
}
}
void IAuthenticationTokenProvider.Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
void IAuthenticationTokenProvider.Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
My code is based on this samples:
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
I would like to use the same sent refresh token, but I have no idea how to use the already sent one in this context.
Any ideas?
Disclaimer: I don't condone reusing refresh tokens.
However, this does provide a good opportunity for everyone to improve knowledge of how this process works and there could be a good reason for reusing past refresh tokens in certain scenarios. I'm basing my answer upon:
Question: "I want a way to use the same refresh token i sent and not reuse a new one."
Code comment, "//HERE I regenerate the token, but I have no idea how to retrieve the already sent one."
PseudoCode Steps:
Store a user identifier as a property in AuthenticationProperties in the GrantResourceOwnerCredentials() method. From the sample code, it looks like you may already be doing this with "userName":
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
},{
"userName", context.UserName
}
});
Retrieve the user identifier in the CreateAsync() method of your IAuthenticationTokenProvider implementation (e.g. "SimpleRefreshTokenProvider" in your case). This would look something like:
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var userName = context.Ticket.Properties.Dictionary["userName"];
...
Still in the CreateAsync() method use the user identifier to lookup the existing refresh token. This would look something like:
var existingRefreshToken = await _repo.FindRefreshTokenByUserNameAsync(userName);
Note: You would need to write the above method into your AuthRepository class from the example code. The "FindRefreshTokenByUserNameAsync(userName) implementation might include something like this if you're using Entity Framework and have a "RefreshToken" table that is being used to persist the granted refresh token:
var existingToken = RefreshToken.Where(r => r.UserName == userName).SingleOrDefault();
At this point, you have the existing token and should be able to re-use that refresh token value instead of Guid.NewGuid():
var refreshTokenId = existingToken.Token;
Taking a look at the tutorial's example code, however, indicates that a HashAlgorithm is being used to store the refresh token's value. That could complicate things a bit for you as storing a hash value is better security, but the process of hashing here is meant to be one-way.
If you really want to reuse the original token value when all you have persisted is the hashed token, would need to implement code that captures the non-hashed token value in the ReceiveAsync() method. It would have to temporarily persist the non-hashed value long enough for you to use it in the CreateAsync() method. In other words, you would have to save/persist the "context.Token" in ReceiveAsync(), associate it with your userName (from context.Ticket.Properties.Dictionary["userName"]), and use it later in the CreateAsync() method. It's hacky and I don't like it, but you would do it around this line of code in ReceiveAsync():
string hashedTokenId = Helper.GetHash(context.Token);

ServiceStack user session not found when using sessionId in client Headers or Cookies

I am using ServiceStack v4 with custom Authentication. This is setup and working correctly. I can call the /auth service and get a returned AuthorizationResponse with unique SessionId.
I also have swagger-ui plugin setup. Using it, I can authenticate via /auth and then call one of my other services which require authentication without issue.
Now, from a secondary MVC application using the c# JsonServiceClient I can again successfully make a call to /auth and then secured services using the same client object. However, if I dispose of that client (after saving the unique sessionId to a cookie), then later create a new client, and either add the sessionId as a Cookie or via headers using x-ss-pid as documented, calling a services returns 401. If I call a non-secure service, but then try to access the unique user session, it returns a new session.
If I look at the request headers in that service, the cookie or Header is clearly set with the sessionId. The sessionId also exists in the sessionCache. The problem seems to be that the code which tries to get the session from the request isn't finding it.
To be more specific, it appears that ServiceExtensions.GetSessionId is looking at the HostContext and not the calling Request. I'm not sure why. Perhaps I misunderstand something along the way here.
If I directly try and fetch my expected session with the following code it's found without issue.
var req = base.Request;
var sessionId = req.GetHeader("X-" + SessionFeature.PermanentSessionId);
var sessionKey = SessionFeature.GetSessionKey(sessionId);
var session = (sessionKey != null ? Cache.Get<IAuthSession>(sessionKey) : null)?? SessionFeature.CreateNewSession(req, sessionId);
So, am I missing something obvious here? Or maybe not so obvious in creating my secondary client?
Sample code of client calls
Here is my authorization code. It's contained in a Controller class. This is just the relevant parts.
using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
try
{
loginResult = client.Post(new Authenticate()
{
UserName = model.Email,
Password = model.Password,
RememberMe = model.RememberMe
});
Response.SetCookie(new HttpCookie(SessionFeature.PermanentSessionId, loginResult.SessionId));
return true;
}
}
Here is my secondary client setup and service call, contained in it's own controller class in another area of the MVC application
using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
var cCookie = HttpContext.Request.Cookies.Get(SessionFeature.PermanentSessionId);
if (cCookie != null)
{
client.Headers.Add("X-" + SessionFeature.PermanentSessionId, cCookie.Value);
client.Headers.Add("X-" + SessionFeature.SessionOptionsKey, "perm");
}
response = client.Get(new SubscriptionStatusRequest());
}
Additional Update
During the Authenticate process the following function is called from HttpRequestExtensions with the name = SessionFeature.PermanentSessionId
public static class HttpRequestExtensions
{
/// <summary>
/// Gets string value from Items[name] then Cookies[name] if exists.
/// Useful when *first* setting the users response cookie in the request filter.
/// To access the value for this initial request you need to set it in Items[].
/// </summary>
/// <returns>string value or null if it doesn't exist</returns>
public static string GetItemOrCookie(this IRequest httpReq, string name)
{
object value;
if (httpReq.Items.TryGetValue(name, out value)) return value.ToString();
Cookie cookie;
if (httpReq.Cookies.TryGetValue(name, out cookie)) return cookie.Value;
return null;
}
Now what occurs is the httpReq.Items contains a SessionFeature.PermanentSessionId value, but I have no clue why and where this gets set. I don't even understand at this point what the Items container is on the IRequest. The code thus never gets to the functionality to check my cookies or headers
The Session wiki describes the different cookies used by ServiceStack Session.
If the client wants to use a Permanent SessionId (i.e. ss-pid), it also needs to send a ss-opt=perm Cookie to indicate it wants to use the permanent Session. This Cookie is automatically set when authenticating with the RememberMe=true option during Authentication.
There was an issue in the Session RequestFilter that was used to ensure Session Id's were attached to the current request weren't using the public IRequest.GetPermanentSessionId() API's which also looks for SessionIds in the HTTP Headers. This has been resolved with this commit which now lets you make Session requests using HTTP Headers, e.g:
//First Authenticate to setup an Authenticated Session with the Server
var client = new JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate
{
provider = CredentialsAuthProvider.Name,
UserName = "user",
Password = "p#55word",
RememberMe = true,
});
//Use new Client instance without Session Cookies populated
var clientWithHeaders = new JsonServiceClient(BaseUrl);
clientWithHeaders.Headers["X-ss-pid"] = authResponse.SessionId;
clientWithHeaders.Headers["X-ss-opt"] = "perm";
var response = clientWithHeaders.Send(new AuthOnly()); //success
This fix is available from v4.0.37+ that's now available on MyGet.
However, if I dispose of that client (after saving the unique sessionId to a cookie)
If the client is disposed where is the cookie you are saving the sessionId located? This answer might provide some additional information.
then later create a new client, and either add the sessionId as a Cookie or via headers using x-ss-pid as documented, calling a services returns 401
If you store/save a valid sessionId as a string you should be able to supply it within a CookieContainer of a new client (given the sessionId is still authenticated). I know you said you tried adding the sessionId as a Cookie but I don't a see sample within your question using the CookieContainer so it should look something like...
using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
var cCookieId = savedCookieId; //a string that I believe you saved from a successfully authenticated client that is now disposed
if (cCookieId != null)
{
var cookie = new Cookie(SessionFeature.PermanentSessionId, cCookieId);
//cookie.Domian = "somedomain.com" //you will probably need to supply this as well
client.CookieContainer.Add(cookie)
}
response = client.Get(new SubscriptionStatusRequest());
}

How to send Json type of input in the post method

i have a set of rest APIs services.am creating a proxy layer above the rest API service.It has login method with POST format and it accepts input in the form of json.I created a proxy layer and am sending the user namenpassword from URL to the Rest service.I created an entity for login which has 2 properties.[user name & password]
Here is the Code:
public void Login([FromUri] string userName, [FromUri]string password)
{
string jsonParams = string.Empty;
LoginData obj = new LoginData();
obj.username = userName;
obj.password = password;
jsonParams = JsonConvert.SerializeObject(obj);
string LoginUrl = "http://restservice/account/login/"
var result = Utils.SendGETRequest(LoginUrl, jsonParams);
}
above code works fine.once login is successful,It wil return a messgae as "success".My question is how to convert the above method into POST because i don't want to send username,password using url.I just want to know how to send JSON type of input.
I think what you want is the WebRequest, probably most specifically a HttpWebRequest. That way you can let the System package do most of the heavy lifting for you.
Check out the HttpClient class. This allows you to send http posts using the
httpClient.PostAsync(url, content) method. As it's an asynchronous method you can also utilise the new async features in C# 5.

Resources