Rest Service securization using JWT - jax-rs

I am trying to implement a token-based authentication on my web service.
I followed this tutorial : Tutoriel
First, when I get a token from the web service and I test it here : Website to test JWT Token I got a the message : invalid signature
And when I tried to identify my token from my web service (between my application and the ws), this function throws an exception :
Unable to read JSON value: XXXX (some data...)
Here the code to generate a token :
private String issueToken(String username) {
SecretKey key = keyGenerator.generateKey();
String jwtToken = Jwts.builder()
.setSubject(username)
.setIssuer(context.getAbsolutePath().toString())
.setIssuedAt(new Date())
.setExpiration(Date.from(LocalDateTime.now().plusMinutes(60L).toInstant(ZoneOffset.UTC)))
.signWith(SignatureAlgorithm.HS512, key)
.compact();
return jwtToken;
}
And here the code to check if the sent token is valid :
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Extract the token from the HTTP Authorization header
String token = "";
if(authorizationHeader != null)
token = authorizationHeader.substring("Bearer".length()).trim();
try {
// Validate the token
SecretKey key = keyGenerator.generateKey();
System.out.println(token);
System.out.println(key);
Jwts.parser().setSigningKey(key).parseClaimsJws(token);
} catch (Exception e) {
System.out.println(e.getMessage());
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
Thanks in advance.

Resolved, thanks to #jps :
"so your line "Token comparison" is the output from filter, right?! Then it's missing the first 6 characters, which explains the excpetion you get. The 6 characters get probably deleted in token = authorizationHeader.substring("Bearer".length()).trim(); . I guess you didn't add the word 'Bearer' to the request and now, instead of deleting 'Bearer' it deletes the first 6 characters of the token"

Related

Create Principal in Guice Filter

I am trying to implement a custom authentication filter in Guice. I receive the token, get the username and realm from the token and then create a Principal. Now I am stuck and I don't know how to set the Principal. It would be nice if I could just set it like this request.setUserPrincipal(principal);, but obviously I can't.
How can I do this?
My doFilter method looks like this:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.length() > 0) {
String token = authorizationHeader.substring("Bearer".length()).trim();
if (token.length() > 0) {
try {
Credentials credentials = securityService.getCredentials(token);
String username = credentials.getUsername();
String realm = credentials.getRealm();
Principal principal = new HttpPrincipal(username, realm);
// request.setUserPrincipal(principal);
LOGGER.info(credentials);
} catch (Exception e) {
LOGGER.error(e);
}
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
The servlet spec section 13.10 says:
The container establishes the caller identity of a request prior to
dispatching the request to the servlet engine. The caller identity
remains unchanged throughout the processing of the request or until
the application sucessfully calls authenticate, login or logout on the
request.
That is the reason why there is no setUserPrincipal.
But there are good news. You can provide your own getUserPrincipal because you can provide your own HttpServletRequest object. Any servlet filter can do it. Look at your code, you are calling the chain method with two parameters: the request and the response. There is no need to pass the same objects that you receive.
The spec even provides you with a helper class: HttpServletRequestWrapper. You just create your own request class as a subclass of the wrapper and override any method that you want, like getUserPrincipal.

REST api cacheablity with authorization

I'm building a protected api for a web application.
for each web service call client sends an access token.
when call for a resource depending on the access token it returns different responses.
ex:- call to /employees will return accessible employees only. accessibility will be defined for each access token.
my question is how it's possible to cache the response if it's returned different things depend on the access token.
is the access token part of the request which is considered in caching?
can the API be REST if it's not cacheable?
is partial access to resource allowed in REST?
#DamithK please clear what you want to do i am not getting it.."when call for a resource depending on the access token it returns different responses.
But as much i understand is that you want to authenticate your each api call.
If you are using RestClient for call api you can do it in following way.To call Api
var client = new RestClient(Serviceurl);
var request = new RestRequest("/Apimethod/{Inputs}?oauth_consumer_key=1ece74e1ca9e4befbb1b64daba7c4a24", Method.GET);
IRestResponse response = client.Execute(request);
In your service
public static class Authentication
{
public static bool AuthenticateRequest(IncomingWebRequestContext context)
{
bool Authenticated = false;
try
{
NameValueCollection param = context.UriTemplateMatch.QueryParameters;
if (param != null && param["oauth_consumer_key"] != null)
{
string consumerSecretKey = "1ece74e1ca9e4befbb1b64daba7c4a24";
Authenticated = param["oauth_consumer_key"] == consumerSecretKey;
}
else
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
}
}
catch (Exception)
{
}
return Authenticated;
}
}
Validate each request in called method using
Authentication.AuthenticateRequest(WebOperationContext.Current.IncomingRequest)
All this is c# code

Basic Auth to Receive Token in Spring Security

I am implementing a RESTful API where the user must authenticate. I want the user to POST their credentials in order to receive a JSON web token (JWT), which is then used for the remainder of the session. I have not found any good sources of information to set this up. In particular, I'm having trouble with the filter. Does anybody have any information or tutorials to help me set this up?
The people at Stormpath have quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
By the way, you can also completely delegate the login/register/logout functionality to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/**
* Authenticates via username (or email) and password and returns a new access token using the Account's ApiKey
*/
public String getAccessToken(String usernameOrEmail, String password) {
ApiKey apiKey = null;
try {
AuthenticationRequest request = new UsernamePasswordRequest(usernameOrEmail, password);
AuthenticationResult result = application.authenticateAccount(request);
Account account = result.getAccount();
ApiKeyList apiKeys = account.getApiKeys();
for (ApiKey ak : apiKeys) {
apiKey = ak;
break;
}
if (apiKey == null) {
//this account does not yet have an apiKey
apiKey = account.createApiKey();
}
} catch (ResourceException exception) {
System.out.println("Authentication Error: " + exception.getMessage());
throw exception;
}
return getAccessToken(apiKey);
}
private String getAccessToken(ApiKey apiKey) {
HttpRequest request = createOauthAuthenticationRequest(apiKey);
AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
return accessTokenResult.getTokenResponse().getAccessToken();
}
private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
try {
String credentials = apiKey.getId() + ":" + apiKey.getSecret();
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});
Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
parameters.put("grant_type", new String[]{"client_credentials"});
HttpRequest request = HttpRequests.method(HttpMethod.POST)
.headers(headers)
.parameters(parameters)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Then, for every authenticated request, your backend will do:
/** This is your protected API */
public void sayHello(String accessToken) throws OauthAuthenticationException {
try {
if (verify(accessToken)) {
doStartEngines(); //Here you will actually call your internal doStartEngines() operation
}
} catch (OauthAuthenticationException e) {
System.out.print("[Server-side] Engines not started. accessToken could not be verified: " + e.getMessage());
throw e;
}
}
private boolean verify(String accessToken) throws OauthAuthenticationException {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
System.out.println(result.getAccount().getEmail() + " was successfully verified");
return true;
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.
Please take a look here for more information.
Hope that helps!
Disclaimer, I am an active Stormpath contributor.
Here's a working sample code from Spring Security OAuth github.
https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/jwt
You probably don't even need to mess with the filters as shown in the above example. If you've custom needs, please post some sample code.

dropbox access token for others to upload to my folder

I plan to have a server program fetching my dropbox account access token and pass to
client program to uplaod to my dropbox folder. Client does not need DB account or login and is able to send file to my DB folder (thus NOT using OAuth ...). Something similar to:
this
and this
but without user upload to server first, i.e., once user get the access token, they upload directly to DB.
I've tried to use Apache httpclient 4.3 to simulate a browser to perform getting request token, sending login-info to get acces token, but get stuck on upload the file via post to a form. Error is HTTP 400 Bad Request ...
executing request:GET https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Request Token: moiejtzdLqTA_0sh3gQyNZAI
executing request:POST https://www.dropbox.com/login HTTP/1.1
----------------------------------------
HTTP/1.1 200 OK
Access Token: 5Ot52QKDbDPSsL1ApU4MIapJ
executing request:POST https://dl-web.dropbox.com/upload?
name=sample.jpg&dest=upload&cookie_t=5Ot52QKDbDP....SsJ&t=5Ot5...apJ HTTP/1.1
----------------------------------------
HTTP/1.1 400 Bad Request
I used Firefox LiveHttpHeader to capture the headers as I do the login and upload file, and saw the post to file upload actually is doing this (and reflect in the code):
https://dl-web.dropbox.com/chunked_upload?
name=tmp1.jpg
&chunk=0
&chunks=1
&bjar=W3sic2Vzc1..............Q%253D%253D
&blid=AAAw4tn................2cDxA
&cookie_t=32yq........nw6c34o
&dest=
&t=32yqVof........c34o
&reported_total_size=5611
&upload_id=1BKGRRP5TpCEjcWSu5tmpQ
&offset=0
So apparrently I missed some param but can't figure out what. The access token seems to be valid as I can see my account info in the return from a httpclinet post to https://www.dropbox.com/home, but the upload simply not working. Anyone has similar experience and getting HTTP 400 error ? .... Many Thanks !
Some code as below:
Constructor and main():
// constructor ...
public HttpClientExample() {
gcookies = new BasicCookieStore();
globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
// Create local HTTP context
ghttpContext = HttpClientContext.create();
ghttpContext.setCookieStore(gcookies);
//
redirectStrategy = new LaxRedirectStrategy(); // for http redirect ...
httpclient = HttpClients.custom()
.setDefaultRequestConfig(this.globalConfig)
.setDefaultCookieStore(this.gcookies)
.setRedirectStrategy(redirectStrategy)
.build();
} // constructor ...
public static void main(String[] args) throws Exception {
HttpClientExample myhttp = new HttpClientExample();
try {
this.localConfig = RequestConfig.copy(this.globalConfig)
.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
.build();
String requestToken = this.getRequestToken(httpclient, loginurl);
theAccessToken = this.postForAccessToken(requestToken, loginurl);
String localFileTopassIn = this.localPath ;
this.postToUpload(httpclient, this.theAccessToken, localFileTopassIn , this.dropboxFolderOnlyName);
}
}
Get the request token:
private String getRequestToken(HttpClient client, String theURL) throws Exception {
HttpGet httpget = new HttpGet(theURL);
httpget.setConfig(localConfig);
httpget.setHeader("Connection", "keep-alive");
System.out.println("\nexecuting request:" + httpget.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(gvcString) == -1) ) {
gvc = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(tString) == -1) ) {
requestToken = aCookie.getValue();
}
}
System.out.println("Request Token: " + requestToken );
return requestToken;
}
postForAccessToken:
private String postForAccessToken(HttpClient client, String requestToken, String theURL) throws Exception{
/*
* Send a post together with request token and my login to get accessToken ...
*/
HttpPost httppost = new HttpPost(theURL); // loginurl);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
List params = new LinkedList();
params.add(new BasicNameValuePair("login_email", myemail));
params.add(new BasicNameValuePair("login_password", mypasswd));
params.add(new BasicNameValuePair("t", requestToken));
HttpEntity postentity = new UrlEncodedFormEntity(params);
httppost.setEntity(postentity);
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(tString) == -1) ) {
theAccessToken = aCookie.getValue();
}
}
System.out.println("Access Token: " + theAccessToken );
return theAccessToken;
}
postToUpload:
private String postToUpload(HttpClient client, String accessToken, String localFileInfo, String destPath) throws Exception{
String bjarString = "bjar";
String blidString = "blid";
String bjar=null;
String blid=null;
List cookies = gcookies.getCookies();
for (Cookie aCookie: cookies) {
String cookieName = aCookie.getName();
if ( !(cookieName.lastIndexOf(bjarString) == -1) ) {
bjar = aCookie.getValue();
} else if ( !(cookieName.lastIndexOf(blidString) == -1) ) {
blid = aCookie.getValue();
}
}
String[] fileNameArry = localFileInfo.split("(\\\\|/)");
String filename = fileNameArry[fileNameArry.length - 1]; // get the last part ...
URI uri = new URIBuilder()
.setScheme("https")
.setHost("dl-web.dropbox.com")
.setPath("/upload")
.setParameter("name", filename)
.setParameter("dest", destPath)
.setParameter("cookie_t", accessToken)
.setParameter("t", accessToken)
.build();
HttpPost httppost = new HttpPost(uri);
httppost.setConfig(localConfig);
ghttpContext.setCookieStore(gcookies);
FileBody bin = new FileBody(new File(localFileInfo));
StringBody comment = new StringBody("A binary file of some kind", ContentType.DEFAULT_BINARY);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("bin", bin)
.addPart("comment", comment)
.build();
httppost.setEntity(reqEntity);
// add header
httppost.setHeader("Host", "www.dropbox.com");
httppost.setHeader("User-Agent", USER_AGENT);
httppost.setHeader("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httppost.setHeader("Connection", "keep-alive");
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httppost.setHeader("Pragma", "no-cache");
httppost.setHeader("Cache-Control", "no-cache");
// add entity
System.out.println("\nexecuting request:" + httppost.getRequestLine());
// Create a custom response handler
ResponseHandler responseHandler = new ResponseHandler() {
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 ) { // && status
OAuth is the only way to use the Dropbox API. Once you have an OAuth access token (which you get by authenticating once, in this case with your account), you just need to do an HTTP PUT to https://api-content.dropbox.com/1/files_put/auto/<path> with the header Authorization: Bearer <token> and the contents of the file in the body.
Note that anyone who has your access token can also delete all your files, upload their personal DVD collection, etc. So it's not recommended that you share that access token.
There is files_get_temporary_upload_link:
Get a one-time use temporary upload link to upload a file to a Dropbox location.
This endpoint acts as a delayed upload. The returned temporary upload link may be used to make a POST request with the data to be uploaded. The upload will then be perfomed with the CommitInfo previously provided to get_temporary_upload_link but evaluated only upon consumption. Hence, errors stemming from invalid CommitInfo with respect to the state of the user's Dropbox will only be communicated at consumption time. Additionally, these errors are surfaced as generic HTTP 409 Conflict responses, potentially hiding issue details. The maximum temporary upload link duration is 4 hours. Upon consumption or expiration, a new link will have to be generated. Multiple links may exist for a specific upload path at any given time.
So you need to have an access token to call this function, but the uploader needs only the produced URL, without access to the rest of the Dropbox vault.

Using Google experimental implementation of OAuth 2.0 to access existing API endpoints

According to this documentation, process of receiving OAuth access token is straightforward. I would like to see a list of all available API endpoints that is ready to accept OAuth 2.0 access token. But for my current needs i would like to somehow receive username and email of a user using OAuth 2.0 access token.
I successfully can receive, for example, data from this endpoint:
https://www.google.com/m8/feeds/contacts/default/full
But unable to receive data from this endpoint:
https://www.googleapis.com/userinfo/email
I tried both header-base and querystring-base approaches of passing single access token. Here is a header i tried:
Authorization: OAuth My_ACCESS_TOKEN
And I even tried OAuth 1.0 version of Authorization header, but... in OAuth 2.0 we do not have secret access token, for instance. Google use bearer tokens in his implementation of OAuth 2.0, so no additional credentials are required.
Anyone successfully received username and email using Google OAuth 2.0?
I found the answer I was looking for. I had to convert PHP to MVC, but pretty easy:
http://codecri.me/case/430/get-a-users-google-email-address-via-oauth2-in-php/
My MVC Login sandbox code looks like the following.
(using JSON.Net http://json.codeplex.com/)
public ActionResult Login()
{
string url = "https://accounts.google.com/o/oauth2/auth?";
url += "client_id=<google-clientid>";
url += "&redirect_uri=" +
// Development Server :P
HttpUtility.UrlEncode("http://localhost:61857/Account/OAuthVerify");
url += "&scope=";
url += HttpUtility.UrlEncode("http://www.google.com/calendar/feeds/ ");
url += HttpUtility.UrlEncode("http://www.google.com/m8/feeds/ ");
url += HttpUtility.UrlEncode("http://docs.google.com/feeds/ ");
url += HttpUtility.UrlEncode("https://mail.google.com/mail/feed/atom ");
url += HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email ");
url += HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.profile ");
url += "&response_type=code";
return new RedirectResult(url);
}
The code returned is proof of Authorization token from the user, which then needs to be turn into a Authentication (accessToken) to access resources.
My MVC OAuthVerify then looks like:
public ActionResult AgentVerify(string code)
{
JObject json;
if (!string.IsNullOrWhiteSpace(code))
{
NameValueCollection postData = new NameValueCollection();
postData.Add("code", code);
postData.Add("client_id", "<google-clientid>");
postData.Add("client_secret", "<google-client-secret>");
postData.Add("redirect_uri", "http://localhost:61857/Account/OAuthVerify");
postData.Add("grant_type", "authorization_code");
try
{
json = JObject.Parse(
HttpClient.PostUrl(
new Uri("https://accounts.google.com/o/oauth2/token"), postData));
string accessToken = json["access_token"].ToString();
string refreshToken = json["refresh_token"].ToString();
bool isBearer =
string.Compare(json["token_type"].ToString(),
"Bearer",
true,
CultureInfo.CurrentCulture) == 0;
if (isBearer)
{
json = JObject.Parse(
HttpClient.GetUrl(
new Uri("https://www.googleapis.com/oauth2/v1/userinfo?alt=json"),
accessToken));
string userEmail = json["email"].ToString();
}
return View("LoginGood");
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex); //ELMAH
}
}
return View("LoginBad");
}
To complete how everything works, I've included the HttpClient utility I created in case anyone needed it.
public class HttpClient
{
public static string GetUrl(Uri url, string OAuth)
{
string result = string.Empty;
using (WebClient httpClient = new WebClient())
{
httpClient.Headers.Add("Authorization","OAuth " + OAuth);
result = httpClient.DownloadString(url.AbsoluteUri);
}
return result;
}
public static string PostUrl(Uri url, NameValueCollection formData)
{
string result = string.Empty;
using (WebClient httpClient = new WebClient())
{
byte[] bytes = httpClient.UploadValues(url.AbsoluteUri, "POST", formData);
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
}
Again, this is test code just to get it to function, I do not recommend using this as-is in a production environment.
try this:
curl -k https://www.googleapis.com/userinfo/email -H "Authorization: OAuth 1/g5_039aCIAfEBuL7OCyB31n1URYU5tUIDudiWKuxN1o"
output: email=name#gmail.com&isVerified=tru