I am working on WSO2IS, and had been able to get a self contained access token out of WSO2IS by Oauth2 "password" grant type by following this post
I am also able to verify the signature of the token in application (see this post)
yet there is still one final step that I can not pass
here is a sample of access token I have got out of WSO2IS
{iss=https://localhost:9443/oauth2/token, sub=wjz#carbon.super, aud=[J3lbMMMJFwXB6neKzXv030S9lfga], exp=1488710173, iat=1488706573, azp=J3lbMMMJFwXB6neKzXv030S9lfga}
you can see that value of "sub" is a username, which correspond to the claim " http://wso2.org/claims/username".
I want to change the configure in WSO2IS so that the "sub" correspond to claim " http://wso2.org/claims/userid"
I changed the "Claim Configuration" under "Service Providers";
I also changed the "sub" in the "http://wso2.org/oidc/claim" under "Claims". but can not get any success.
are there anything I have missed?
please advise
thanks
I finally have this problem solved by coding instead of configuring.
I had implemented an extension for a Self-Contained Access Token (JWT in Oauth2) Generator by followed this post . I build the jar, and upload the jar under /repository/components/lib/
I just checkout this repo , and made the following changes
/**
* For a locally authenticated user, subject identifier is supposed to be as below.
* <userstore_domain>/<username>#<tenant_domain>.
*
* yet somehow, what I got is <username>#<tenant_domain>
* #param SubjectId
* #return
* #throws IdentityOAuth2Exception
*/
private static SubjectTriple parseSubjectId(String subjectId) throws IdentityOAuth2Exception{
if (StringUtils.isBlank(subjectId)){
throw new IdentityOAuth2Exception("invalid subject identifier");
}
/*
* domain may not present
*/
String sid = null;
SubjectTriple st = new SubjectTriple();
if(StringUtils.contains(subjectId, '/')){
st.domain = StringUtils.substringBeforeLast(subjectId, "/");
sid = StringUtils.substringAfterLast(subjectId, "/");
}else{
sid = subjectId;
}
st.username = StringUtils.substringBeforeLast(sid, "#");
st.profile = StringUtils.substringAfterLast(sid, "#");
return st;
}
/**
* To build id token from OauthToken request message context
*
* #param request Token request message context
* #return Signed jwt string.
* #throws IdentityOAuth2Exception
*/
protected String buildIDToken(OAuthTokenReqMessageContext request)
throws IdentityOAuth2Exception {
String issuer = OAuth2Util.getIDTokenIssuer();
long lifetimeInMillis = OAuthServerConfiguration.getInstance().
getApplicationAccessTokenValidityPeriodInSeconds() * 1000;
long curTimeInMillis = Calendar.getInstance().getTimeInMillis();
SubjectTriple triple = parseSubjectId(request.getAuthorizedUser().getAuthenticatedSubjectIdentifier());
String userId = null;
try {
userId = CarbonContext.getThreadLocalCarbonContext().getUserRealm().getUserStoreManager()
.getUserClaimValue(triple.username, Constants.LOCAL_CLAIM__UserID, triple.profile);
} catch (UserStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String clientId = request.getOauth2AccessTokenReqDTO().getClientId();
// Set claims to jwt token.
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet();
jwtClaimsSet.setIssuer(issuer);
jwtClaimsSet.setSubject(userId);
jwtClaimsSet.setAudience(Arrays.asList(clientId));
jwtClaimsSet.setClaim(Constants.AUTHORIZATION_PARTY, clientId);
jwtClaimsSet.setExpirationTime(new Date(curTimeInMillis + lifetimeInMillis));
jwtClaimsSet.setIssueTime(new Date(curTimeInMillis));
if (JWSAlgorithm.NONE.getName().equals(signatureAlgorithm.getName())) {
return new PlainJWT(jwtClaimsSet).serialize();
}
return signJWT(jwtClaimsSet, request);
}
/**
* Build a signed jwt token from authorization request message context
*
* #param request Oauth authorization message context
* #return Signed jwt string
* #throws IdentityOAuth2Exception
*/
protected String buildIDToken(OAuthAuthzReqMessageContext request)
throws IdentityOAuth2Exception {
String issuer = OAuth2Util.getIDTokenIssuer();
long lifetimeInMillis = OAuthServerConfiguration.getInstance().
getApplicationAccessTokenValidityPeriodInSeconds() * 1000;
long curTimeInMillis = Calendar.getInstance().getTimeInMillis();
OAuth2AuthorizeReqDTO dto = request.getAuthorizationReqDTO();
SubjectTriple triple = parseSubjectId(dto.getUser().getAuthenticatedSubjectIdentifier());
String userId = null;
try {
userId = CarbonContext.getThreadLocalCarbonContext().getUserRealm().getUserStoreManager()
.getUserClaimValue(triple.username, Constants.LOCAL_CLAIM__UserID, triple.profile);
} catch (UserStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String consumerKey = dto.getConsumerKey();
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet();
jwtClaimsSet.setIssuer(issuer);
jwtClaimsSet.setSubject(userId);
jwtClaimsSet.setAudience(Arrays.asList(consumerKey));
jwtClaimsSet.setClaim(Constants.AUTHORIZATION_PARTY,consumerKey);
jwtClaimsSet.setExpirationTime(new Date(curTimeInMillis + lifetimeInMillis));
jwtClaimsSet.setIssueTime(new Date(curTimeInMillis));
if (JWSAlgorithm.NONE.getName().equals(signatureAlgorithm.getName())) {
return new PlainJWT(jwtClaimsSet).serialize();
}
return signJWT(jwtClaimsSet, request);
}
the imports
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.core.util.KeyStoreManager;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuerImpl;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.user.api.UserStoreException;
import java.security.Key;
import java.security.interfaces.RSAPrivateKey;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Related
I'm trying to use The IBM® Cloud Object Storage SDK for Java and following this explanations https://console.bluemix.net/docs/services/cloud-object-storage/libraries/java.html#client-credentials where it says:
After generating a Service Credential, the resulting JSON document can be saved to ~/.bluemix/cos_credentials. The SDK will automatically source credentials from this file unless other credentials are explicitly set during client creation
So I settled the referenced ~/.bluemix/cos_credentials in place (got it from my IBM cos instance credentials) and i expect to use this file to configure the client instead of coding the values. So now, how can a client be instantiated? Which classes of the sdk are to be used to get a working client configured to work with the bucket?
Here my cos_credentials file
{
"apikey": "xxxxxxxxx",
"endpoints": "https://cos-service.bluemix.net/endpoints",
"iam_apikey_description": "Auto generated apikey during resource-key operation for Instance - crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx::",
"iam_apikey_name": "auto-generated-apikey-xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
"iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Writer",
"iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/xxxxxxxxxxxxxxxxxx::serviceid:ServiceId-xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"resource_instance_id": "crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx::"
}
You should need just a few of the client classes, and none of the credential classes. Here's an example that might help get you started:
import java.sql.Timestamp;
import java.io.File;
import com.ibm.cloud.objectstorage.ClientConfiguration;
import com.ibm.cloud.objectstorage.SDKGlobalConfiguration;
import com.ibm.cloud.objectstorage.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.ibm.cloud.objectstorage.services.s3.AmazonS3;
import com.ibm.cloud.objectstorage.services.s3.AmazonS3ClientBuilder;
import com.ibm.cloud.objectstorage.services.s3.model.ListObjectsRequest;
import com.ibm.cloud.objectstorage.services.s3.model.ObjectListing;
import com.ibm.cloud.objectstorage.services.s3.model.S3ObjectSummary;
public class CredentialsFile
{
private static AmazonS3 _s3Client;
/**
* #param args
*/
public static void main(String[] args)
{
SDKGlobalConfiguration.IAM_ENDPOINT = "https://iam.bluemix.net/oidc/token";
String bucketName = "<bucket-name.";
String objectKey = "<object-key";
String filePath = "/absolute/path/to/file";
String endpoint_url = "https://s3-api.us-geo.objectstorage.softlayer.net";
String location = "us";
System.out.println("Current time: " + new Timestamp(System.currentTimeMillis()).toString());
_s3Client = createClient(endpoint_url, location);
newObject(bucketName, objectKey, filePath, _s3Client);
listObjects(bucketName, _s3Client);
}
/**
* #param bucketName
* #param clientNum
* #param endpoint_url
* #param location
* #return AmazonS3
*/
public static AmazonS3 createClient(String endpoint_url, String location)
{
ClientConfiguration clientConfig = new ClientConfiguration().withRequestTimeout(5000);
clientConfig.setUseTcpKeepAlive(true);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withEndpointConfiguration(new EndpointConfiguration(endpoint_url, location)).withPathStyleAccessEnabled(true)
.withClientConfiguration(clientConfig).build();
return s3Client;
}
/**
* #param bucketName
* #param keyName
* #param filePath
* #param s3Client
*/
public static void newObject(String bucketName, String keyName, String filePath, AmazonS3 s3Client)
{
System.out.println("Uploading new object " + keyName + " from " + filePath + "...");
s3Client.putObject(bucketName, keyName, new File(filePath));
System.out.println(keyName +" uploaded successfully.");
}
/**
* #param bucketName
* #param s3Client
*/
public static void listObjects(String bucketName, AmazonS3 s3Client)
{
System.out.println("Listing objects in bucket " + bucketName);
ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest().withBucketName(bucketName));
for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
System.out.println(" - " + objectSummary.getKey() + " " + "(size = " + objectSummary.getSize() + ")");
}
System.out.println();
}
}
I am trying to use Zoom API which requires using JWT. I have successfully using node.js to generate JWT and call the Zoom API like this:
var jwt = require('jsonwebtoken');
var zoom_key = "abcd";
var zoom_secret = "efgh";
var payload = {
iss: Zoom_Key,
exp: ((new Date()).getTime() + 3600)
};
//Automatically creates header, and returns JWT
var token = jwt.sign(payload, zoom_secret);
module.exports = token;
However, right now I am trying to use the same way in JAVA. When I using the token by JJWT, it always give the the "invalid token" error message from zoom api. Can any one help me figure out the reason?
First, I create a Playload class in Playload.java like this:
// in Playload.java
package palyload;
public class Playload {
public String iss;
public Playload(String iss) {
this.iss = iss;
}
}
Second,
I import JJWT and play.libs.Json to generate JWT token like this:
package controllers;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import palyload.Playload;
public class JWT extends Controller {
private static final String zoom_key = "abcd";
private static final String zoom_secret = "efgh";
private static final String baseUrl = "https://api.zoom.us/v2/users/?access_token=";
public String setToken (Object obj) {
String token = "";
Map<String, Object> map = new HashMap<>();
map.put("json", Json.toJson(obj));
try {
token = Jwts.builder()
.setClaims(map)
.setExpiration(Date.from(ZonedDateTime.now(ZoneId.systemDefault()).plusSeconds(3600).toInstant()))
.signWith(SignatureAlgorithm.HS256, zoom_secret)
.compact();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println(Jwts.parser().setSigningKey(zoom_secret).parseClaimsJws(token).getBody().getSubject().toString());
// System.out.println(map.toString());
return token;
}
public String getToken () {
Playload pl = new Playload(zoom_key);
System.out.println("playload: " + Json.toJson(pl).toString());
return setToken(pl);
}
public String setUrl () {
return baseUrl + getToken();
}
public Result getUrl () {
return ok(setUrl());
}
}
Have no idea why this token url is not correct like Node.js one?
I am working on Arnab's tutorial on Volley from this site. I am getting a NullPointerException while making an asmx web service call for JSON data object from Android App using Volley in Android Studio. The "req" variable is causing the error in line 84 but I clearly declare it before the offending line of code is run. Here is the error from the monitor:
FATAL EXCEPTION: main
Process: com.caduceususa.app.myApp, PID: 14603
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.caduceususa.app.myApp.ApplicationController.addToRequestQueue(com.android.volley.Request)' on a null object reference
at com.caduceususa.app.myApp.ConsumeWS$1.onClick(ConsumeWS.java:84)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I have three JAVA files in this project. The first contains onCreate here:
package com.caduceususa.app.myApp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
public class ConsumeWS extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_consume_ws);
final Button submit = (Button) findViewById(R.id.submit);
final TextView status = (TextView)findViewById(R.id.connStatus);
final TextView response = (TextView)findViewById(R.id.serverResp);
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
status.setText("Connection Requested...");
response.setText("waiting...");
JSONObject oCreds = new JSONObject();
final String URL = "https://myApp.caduceususa.com/ws/myApp.asmx/myAppLogin";
HashMap<String, String> params = new HashMap<String, String>();
params.put("sName", "email#email.com");
params.put("sPass", "password");
JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
VolleyLog.v("Response:%n %s", response.toString(4));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
});
// add the request object to the queue to be executed
ApplicationController.getInstance().addToRequestQueue(req);
}
});
}
public class JsonObjectRequest extends JsonRequest<JSONObject> {
/**
* Creates a new request.
* #param method the HTTP method to use
* #param url URL to fetch the JSON from
* #param jsonRequest A {#link JSONObject} to post with the request. Null is allowed and
* indicates no parameters will be posted along with request.
* #param listener Listener to receive the JSON response
* #param errorListener Error listener, or null to ignore errors.
*/
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
Listener<JSONObject> listener, ErrorListener errorListener) {
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
errorListener);
}
/**
* Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
* <code>null</code>, <code>POST</code> otherwise.
*
* #see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
*/
public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
ErrorListener errorListener) {
this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
listener, errorListener);
}
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
}
My ApplicationController JAVA file is as follows:
package com.caduceususa.app.myApp;
import android.app.Application;
import android.text.TextUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.Volley;
public class ApplicationController extends Application {
/**
* Log or request TAG
*/
public static final String TAG = "VolleyPatterns";
/**
* Global request queue for Volley
*/
private RequestQueue mRequestQueue;
/**
* A singleton instance of the application class for easy access in other places
*/
private static ApplicationController sInstance;
#Override
public void onCreate() {
super.onCreate();
// initialize the singleton
sInstance = this;
}
/**
* #return ApplicationController singleton instance
*/
public static synchronized ApplicationController getInstance() {
return sInstance;
}
/**
* #return The Volley Request queue, the queue will be created if it is null
*/
public RequestQueue getRequestQueue() {
// lazy initialize the request queue, the queue instance will be
// created when it is accessed for the first time
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
/**
* Adds the specified request to the global queue, if tag is specified
* then it is used else Default TAG is used.
*
* #param req
* #param tag
*/
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
VolleyLog.d("Adding request to queue: %s", req.getUrl());
getRequestQueue().add(req);
}
/**
* Adds the specified request to the global queue using the Default TAG.
*
* #param req
* #param tag
*/
public <T> void addToRequestQueue(Request<T> req) {
// set the default tag if tag is empty
req.setTag(TAG);
getRequestQueue().add(req);
}
/**
* Cancels all pending requests by the specified TAG, it is important
* to specify a TAG so that the pending/ongoing requests can be cancelled.
*
* #param tag
*/
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
And here is an error helper:
package com.caduceususa.app.myApp;
import android.content.Context;
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkError;
import com.android.volley.NetworkResponse;
import com.android.volley.NoConnectionError;
import com.android.volley.ServerError;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.HashMap;
import java.util.Map;
public class VolleyErrorHelper {
/**
* Returns appropriate message which is to be displayed to the user
* against the specified error object.
*
* #param error
* #param context
* #return
*/
public static String getMessage(Object error, Context context) {
if (error instanceof TimeoutError) {
return context.getResources().getString(R.string.generic_server_down);
}
else if (isServerProblem(error)) {
return handleServerError(error, context);
}
else if (isNetworkProblem(error)) {
return context.getResources().getString(R.string.no_internet);
}
return context.getResources().getString(R.string.generic_error);
}
/**
* Determines whether the error is related to network
* #param error
* #return
*/
private static boolean isNetworkProblem(Object error) {
return (error instanceof NetworkError) || (error instanceof NoConnectionError);
}
/**
* Determines whether the error is related to server
* #param error
* #return
*/
private static boolean isServerProblem(Object error) {
return (error instanceof ServerError) || (error instanceof AuthFailureError);
}
/**
* Handles the server error, tries to determine whether to show a stock message or to
* show a message retrieved from the server.
*
* #param err
* #param context
* #return
*/
private static String handleServerError(Object err, Context context) {
VolleyError error = (VolleyError) err;
NetworkResponse response = error.networkResponse;
if (response != null) {
switch (response.statusCode) {
case 404:
case 422:
case 401:
try {
// server might return error like this { "error": "Some error occured" }
// Use "Gson" to parse the result
HashMap<String, String> result = new Gson().fromJson(new String(response.data),
new TypeToken<Map<String, String>>() {
}.getType());
if (result != null && result.containsKey("error")) {
return result.get("error");
}
} catch (Exception e) {
e.printStackTrace();
}
// invalid request
return error.getMessage();
default:
return context.getResources().getString(R.string.generic_server_down);
}
}
return context.getResources().getString(R.string.generic_error);
}
}
Finally here is my AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.caduceususa.app.myApp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".ConsumeWS">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I am really not sure where to start to debug here as I have seen multiple suggested solutions that which I have tried and I figure let me just put the code out there and maybe someone can help me.
Add ApplicationController class in manifest tag, because it is missing that android:name attribute. As it is not referenced there that is why you are getting NPE.
Disclaimer: I am the author of that blog post from where this piece of code is referenced (volley usage part)
In Java, I try to set up a JWT authentication on a Rest API using jersey 1.9.
I'm using a friend's code sample (his token are valid with that code) and io.jsonwebtoken to generate token but I keep getting an Invalid signature warning when I test them on https://jwt.io/.
I've done some research and tried to fix that but I'm running out of ideas.
Example of invalid token I get with that code:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyIiwiaWF0IjoxNDg1MDI2MDgzLCJzdWIiOiJodHRwOi8vbG9jYWxob3N0OjkxODAvVHJvY1RvblNhdm9pci8iLCJpc3MiOiJzZXJnZW50LWNoZWYiLCJleHAiOjE1MTY1NjIwODN9.HY8S7QbOhSB22d1_Dkmtg6qCiKxQRKz9W1etMqDookw
This is the login path and the method I use to create those token :
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.xml.bind.DatatypeConverter;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.jsonwebtoken.impl.crypto.MacProvider;
import dao.UserDao;
import model.User;
#Path("/home")
public class MainController {
UserController userCtrl = new UserController();
//The not really secret key
String key = "supersecretkey";
#POST
#Path("login")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response Login(
#FormParam("username") String username,
#FormParam("password") String password){
if (username == null || password == null) {
return Response
.status(Status.PRECONDITION_FAILED)
.build();
}
User user = userCtrl.Authenticate(username,password);
if (user == null) {
return Response
.status(Status.FORBIDDEN)
.build();
}
String token = createJWT(user.getUserID()+"",user.getUserName(),"http://localhost:8080/rest_api/",TimeUnit.DAYS.toMillis(365));
return Response
.status(Status.OK)
.entity(token)
.build();
}
private String createJWT(String id, String issuer, String subject, long ttlMillis) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(key);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey );
//if it has been specified, let's add the expiration
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
}
Solved
I don't really know what was wrong with my secret key but I manage to validate my token by changing my key generation:
private static final Key secret = MacProvider.generateKey(SignatureAlgorithm.HS256);
private static final byte[] secretBytes = secret.getEncoded();
public static final String base64SecretBytes = Base64.getEncoder().encodeToString(secretBytes);
I am trying to upload a file, I am trying to change the default location of the uploaded file. How to change this please suggest ?
package Controller;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import requests.Connect;
import display.DisplayLog;
/** * Servlet implementation class ControlServlet
*/
public class ControlServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
boolean result;
private boolean isMultipart;
private String filePath;
private int maxFileSize = 1000 * 1024;
private int maxMemSize = 1000 * 1024;
private File file ;
public ControlServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session=request.getSession();
String userName = request.getParameter("username");
isMultipart = ServletFileUpload.isMultipartContent(request);
response.setContentType("audio/mpeg3;audio/x-mpeg-3;video/mpeg;video/x-mpeg;text/xml");
PrintWriter out = response.getWriter( );
if (isMultipart) {
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Parse the request
List items = upload.parseRequest(request);
Iterator iterator = items.iterator();
while (iterator.hasNext()) {
FileItem item = (FileItem) iterator.next();
if (!item.isFormField())
{
String fileName = item.getName();
if (fileName != null) {
fileName = FilenameUtils.getName(fileName);
}
String root = getServletContext().getRealPath("/");
root = "F/images";
File path = new File(root + "/uploads");
if (!path.exists())
{
boolean status = path.mkdirs();
}
File uploadedFile = new File(path + "/" + fileName);
System.out.println(" Prashant File Upload Location is ");
// System.out.println(uploadedFile.getAbsolutePath());
System.out.println("fileName is " +fileName);
System.out.println("root is " + root);
System.out.println("path is " + path);
if(fileName!="")
{
item.write(uploadedFile);
System.out.println(" Prashant File Upload Location 2 is ");
System.out.println(uploadedFile.getAbsolutePath());
out.println("<h1>File Uploaded Successfully....:-)</h1>");
}
else
{
out.println(uploadedFile.getAbsolutePath());
out.println("<h1>File Uploaded Successfully....:-)</h1>");
System.out.println("file not found");
}
}
else
{
String abc = item.getString();
}
}
} catch (FileUploadException e) {
out.println(e);
} catch (Exception e) {
out.println(e);
}
}
else
{
out.println("Not Multipart");
}
System.out.println("print this Prashant" + userName);
session.setAttribute("username",userName);
request.setAttribute("username","prashant");
// RequestDispatcher myDispatch = request.getRequestDispatcher("Index.jsp");
//myDispatch.forward(request, response);
}
}
I am getting this as default folder F:\jboss-4.2.3.GA-jdk6\jboss-4.2.3.GA\bin\ please help i am new to this
Your problem is here:
String root = getServletContext().getRealPath("/");
you are setting the upload path to the containers path, not a default path but the place where the server started from. You can make the upload path anything you want it to be, it depends on your needs and configuration.
You could create a system property with the directory of your choice, you could set it as a dynamic property in a JBoss configuration file (not sure what that would be for JBoss4).