Cannot instantiate the type JsonFactory - android

I am trying to verify a JWT that I am receiving from Google using GoogleAuthUtil. I am trying to use the code at the bottom of this page. Here is my exact source code:
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
public class Checker {
private final List mClientIDs;
private final String mAudience;
private final GoogleIdTokenVerifier mVerifier;
private final JsonFactory mJFactory;
private String mProblem = "Verification failed. (Time-out?)";
public Checker(String[] clientIDs, String audience) {
mClientIDs = Arrays.asList(clientIDs);
mAudience = audience;
NetHttpTransport transport = new NetHttpTransport();
mJFactory = new JsonFactory();
mVerifier = new GoogleIdTokenVerifier(transport, mJFactory);
}
public GoogleIdToken.Payload check(String tokenString) {
GoogleIdToken.Payload payload = null;
try {
GoogleIdToken token = GoogleIdToken.parse(mJFactory, tokenString);
if (mVerifier.verify(token)) {
GoogleIdToken.Payload tempPayload = token.getPayload();
if (!tempPayload.getAudience().equals(mAudience))
mProblem = "Audience mismatch";
else if (!mClientIDs.contains(tempPayload.getIssuee()))
mProblem = "Client ID mismatch";
else
payload = tempPayload;
}
} catch (GeneralSecurityException e) {
mProblem = "Security issue: " + e.getLocalizedMessage();
} catch (IOException e) {
mProblem = "Network problem: " + e.getLocalizedMessage();
}
return payload;
}
public String problem() {
return mProblem;
}
}
The issue that I'm having is in this line: mJFactory = new JsonFactory();, where I am getting the error Cannot instantiate the type JsonFactory. I'm pretty sure I'm calling the constructor properly and I have all of the libraries imported properly so I don't know why I'm getting this error. If anyone can help me out, that would be great! Let me know if theres any additional info that would be helpful.
EDIT:
Here's the link to the Javadoc

Okay the issue was that I made a small mistake copying the code. JsonFactory is an abstract class, so you need to use the subclass GsonFactory to provide an implementation.

Related

How to like/unlike and subscribe a YouTube video from a android app

I'm trying to create a YouTube video android app.Currently there no issue to play video and fetch a playlist because there are sample for this.But I'm unable to find any good reference to like/unlike and subscribe events in YouTube.
So How to like/unlike and subscribe a YouTube video from a android app ?
Any help will be highly appreciated.
I don't think you can do it in your own application.
You will have to redirect the user of your application to the channel he wants to subscribe to through the YouTube App.
You can use this method from the YouTube API : createChannelIntent (link). From there, your user will be able to subscribe to the channel, as it will be opened into the YouTube App.
Make sure that the YouTube App is installed before (link) ! :)
Hope it helps !
You need to use the YouTube Data apis. Here you can read how to like/dislike a video.
maybe you can use this code:
// Sample Java code for user authorization
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.youtube.YouTubeScopes;
import com.google.api.services.youtube.model.*;
import com.google.api.services.youtube.YouTube;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class ApiExample {
/** Application name. */
private static final String APPLICATION_NAME = "API Sample";
/** Directory to store user credentials for this application. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(
System.getProperty("user.home"), ".credentials/java-youtube-api-tests");
/** Global instance of the {#link FileDataStoreFactory}. */
private static FileDataStoreFactory DATA_STORE_FACTORY;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport HTTP_TRANSPORT;
/** Global instance of the scopes required by this quickstart.
*
* If modifying these scopes, delete your previously saved credentials
* at ~/.credentials/drive-java-quickstart
*/
private static final Collection<String> SCOPES = Arrays.asList("YouTubeScopes.https://www.googleapis.com/auth/youtube.force-ssl YouTubeScopes.https://www.googleapis.com/auth/youtubepartner");
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
/**
* Creates an authorized Credential object.
* #return an authorized Credential object.
* #throws IOException
*/
public static Credential authorize() throws IOException {
// Load client secrets.
InputStream in = ApiExample.class.getResourceAsStream("/client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader( in ));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(
flow, new LocalServerReceiver()).authorize("user");
System.out.println(
"Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/**
* Build and return an authorized API client service, such as a YouTube
* Data API client service.
* #return an authorized API client service
* #throws IOException
*/
public static YouTube getYouTubeService() throws IOException {
Credential credential = authorize();
return new YouTube.Builder(
HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
public static void main(String[] args) throws IOException {
YouTube youtube = getYouTubeService();
try {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("id", "E6UTz_Doic8");
parameters.put("rating", "like");
YouTube.Videos.Rate videosRateRequest = youtube.videos().rate(parameters.get("id").toString(), parameters.get("rating").toString());
videosRateRequest.execute();
} catch (GoogleJsonResponseException e) {
e.printStackTrace();
System.err.println("There was a service error: " + e.getDetails().getCode() + " : " + e.getDetails().getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
}
}
can be more complete later,
This

Dictionary app using Oxford Dictionary API

I am trying to make a dictionary application using Oxford Dictionary api. There is something wrong with my code JSON. Can anyone tell me how do I extract only the definition of the searched word, rather getting the whole JSON file
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class MainActivity extends AppCompatActivity {
private static final String APP_ID= "59028fc6";
private static final String API_KEY = "ad3e310307d7b2f8bf474c45e1efd01f";
private static final String TAG = MainActivity.class.getSimpleName();
private OkHttpClient okHttpClient;
private EditText textInput;
private Button submitButton;
private TextView definitionView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// initialize ok http
okHttpClient = new OkHttpClient();
textInput = findViewById(R.id.textInput);
submitButton = findViewById(R.id.submitButton);
definitionView = findViewById(R.id.textMeaning);
submitButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
findMeaningOfEnteredWord();
}
});
}
private void findMeaningOfEnteredWord() {
String word = textInput.getText().toString();
if (word.isEmpty()) {
Toast.makeText(this, "Nothing entered", Toast.LENGTH_SHORT).show();
return;
}
// create url from the word
String lowerCaseWord = word.toLowerCase();
String httpRequestUrl = "https://od-api.oxforddictionaries.com:443/api/v1/entries/en/" + lowerCaseWord;
// make request with REST url
new RequestAsyncTask().execute(httpRequestUrl);
}
private class RequestAsyncTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String requestUrl = params[0];
Request request = new Request.Builder()
.url(requestUrl)
.addHeader("Accept", "application/json")
.addHeader("app_id", APP_ID)
.addHeader("app_key", API_KEY)
.build();
Response response = null;
try {
response = okHttpClient.newCall(request).execute();
return response.body().string();
} catch (IOException ex) {
Log.e(TAG, "caught error: " + ex.getMessage());
}
return "";
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject responseAsJson = new JSONObject(result);
JSONArray results = responseAsJson.getJSONArray("results");
if (results.length() > 0) { // valid definitions were found
String lexicalEntries = results.getJSONObject(0).getString("lexicalEntries");
definitionView.setText(lexicalEntries);
}
Log.d(TAG, " " + responseAsJson.toString());
} catch (Exception ex) {
Log.d(TAG, "exception during json parsing: " + ex.getMessage());
}
}
}
}
JSON:
{"id":"aeroplane",
"language":"en",
"lexicalEntries": [
{
"entries": [{"etymologies":["late 19th century: from French aéroplane, from aéro- ‘air’ + Greek -planos ‘wandering’"],
"grammaticalFeatures":[{"text":"Singular","type":"Number"}],
"homographNumber":"000",
"senses":[{"crossReferenceMarkers":["North American term airplane"],
"crossReferences":[{"id":"airplane","text":"airplane","type":"see also"}],
"definitions":["a powered flying vehicle with fixed wings and a weight greater than that of the air it displaces."],
"domains":["Aviation"],
"id":"m_en_gbus0013220.005",
"regions":["British"],
"short_definitions":["powered flying vehicle with fixed wings"],
"thesaurusLinks":[{"entry_id":"plane","sense_id":"t_en_gb0011151.001"}]}]}],"language":"en","lexicalCategory":"Noun","pronunciations":[{"audioFile":"http:\/\/audio.oxforddictionaries.com\/en\/mp3\/aeroplane_gb_2.mp3","dialects":["British English"],"phoneticNotation":"IPA","phoneticSpelling":"ˈɛːrəpleɪn"}],"text":"aeroplane"}],
"type":"headword","word":"aeroplane"
}
Modify these lines :
String lexicalEntries = results.getJSONObject(0).getString("lexicalEntries");
definitionView.setText(lexicalEntries);
to :
String definition = results.getJSONObject(0).getString("lexicalEntries")
.getJSONArray("entries").getJSONObject(0).getJSONArray("senses")
.getJSONObject(0).getJSONArray("definitions").getString(0);
definitionView.setText(definition);
Of course you may need to modify your UI based on the number of definitions a word has.
Also, you should probably consider using POJOs instead of directly dealing with the JSON response.
I'd recommend Jackson or GSON for doing this.
String definitions=results.getJSONArray("lexicalEntries")
.getJSONObject(0)
.getJSONArray("entries")
.getJSONObject(0)
.getJSONArray("senses")
.getJSONArray("definitions")
.get(0)
So , The thing is , There are a lot of gaps in the JSON for different words .
Which means a word may have an array of "synonyms" but others don't , So in your code you are trying to reach something that doesn't actually exist (a NULL value) which is likely to throw an exception every time you search for a word that the JSON returned doesn't match the JSON you are expecting , Because there are missing (NULL) values .
The app I made using oxford dictionary required a lot of work just to make sure there is no thrown exception .
I used retrofit with moshi converter factory , And then Do the following :
1-In your custom classes , Make sure you annotate every data member with
#Json and provide the name of the keys in the JSON of oxford
2-make sure that every declared type is nullable , including both List and the type inside of it
You'll then be able to get the result , And Now comes the part where you handle evey call that may be null
I know this is a bit old question , But It happened that I struggled with this api once , So I hope this may help someone :)

Problems building Google Drive API File Upload

I am trying to build an android app that'll allow me to upload files to Google Drive upon requirement of the user. But, I can't find a single working example anywhere. There are half baked snippets scattered here and there. Some of them are able to connect through OAuth, others are able to create an empty file or folder, but nowhere I can find an app that saves the tokens, and uploads the files seamlessly. I am just clueless as to how to implement the functionality as no books or videos are available, google's own samples don't work for me. I'm struggling to make the code work. Please help someone. Thanks.
I always use the class below to create a Google drive service.
First you need to have these dependencies on your pom file :
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-drive</artifactId>
<version>v2-rev282-1.23.0</version>
</dependency>
Then use this class to create instance of the drive api client :
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
/**
*
* #author jalal-sordo
*/
public class GoogleDriveServiceFactory {
private String applicationName;
private JsonFactory jsonFactory;
private HttpTransport googleDriveHttpTransport;
private List<String> googleDriveApiScopes;
private String googleDriveClientSecretFilePath;
private FileDataStoreFactory credentialsStoreFolder;
public GoogleDriveServiceFactory(ApplicationParameters params) {
try {
this.googleDriveClientSecretFilePath = params.getGoogleDriveClientSecretFilePath();
// = new FileInputStream(googleDriveClientSecretFilePath);
applicationName = "someApplicationName";
jsonFactory = JacksonFactory.getDefaultInstance();
googleDriveApiScopes = Arrays.asList(DriveScopes.DRIVE);
googleDriveHttpTransport = GoogleNetHttpTransport.newTrustedTransport();
java.io.File googleDriveCredentialsStore = new java.io.File(params.getGoogleDriveCredentialsFolderPath());
credentialsStoreFolder = new FileDataStoreFactory(googleDriveCredentialsStore);
} catch (IOException | GeneralSecurityException t) {
System.err.println(t.getMessage());
System.exit(1);
}
}
public Credential authorize() throws IOException {
InputStreamReader streamReader = new FileReader(new java.io.File(googleDriveClientSecretFilePath));
GoogleClientSecrets clientSecrets
= GoogleClientSecrets.load(jsonFactory, streamReader);
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow
= new GoogleAuthorizationCodeFlow.Builder(
googleDriveHttpTransport, jsonFactory, clientSecrets, googleDriveApiScopes)
.setDataStoreFactory(credentialsStoreFolder)
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(
flow, new LocalServerReceiver()).authorize("user");
return credential;
}
public Drive getDriveService() throws IOException {
Credential credential = authorize();
return new Drive.Builder(
googleDriveHttpTransport, jsonFactory, credential)
.setApplicationName(applicationName)
.build();
}
}
You will also need this class to provide parameters to the class above :
/**
*
* #author jalal-sordo
*/
public class ApplicationParameters {
private String googleDriveCredentialsFolderPath;
private String googleDriveClientSecretFilePath;
public String getGoogleDriveCredentialsFolderPath() {
return googleDriveCredentialsFolderPath;
}
public void setGoogleDriveCredentialsFolderPath(String googleDriveCredentialsFolderPath) {
this.googleDriveCredentialsFolderPath = googleDriveCredentialsFolderPath;
}
public String getGoogleDriveClientSecretFilePath() {
return googleDriveClientSecretFilePath;
}
public void setGoogleDriveClientSecretFilePath(String googleDriveClientSecretFilePath) {
this.googleDriveClientSecretFilePath = googleDriveClientSecretFilePath;
}
#Override
public String toString() {
return "ApplicationParameters{"
+ "\ngoogleDriveCredentialsFolderPath = " + googleDriveCredentialsFolderPath
+ "\ngoogleDriveClientSecretFilePath = " + googleDriveClientSecretFilePath
+ "\n}";
}
}
And this is how you can create an instance of the GoogleDriveServiceFactory and perform a file upload :
ApplicationParameters params = new ApplicationParameters();
//this is where you specify where you want the credentials to be stored
//after a successful autherization is made from the browser (this code will
//open the authorization consent page on your default browser).
params.setGoogleDriveCredentialsFolderPath("/path/to/credentials/folder");
//this is the path to your client_id that you downloaded from google cloud
//console credentials page.
params.setGoogleDriveClientSecretFilePath("/path/to/client_id.json");
GoogleDriveServiceFactory driveFactory = new GoogleDriveServiceFactory (params);
File fileMetadata = new File();
fileMetadata.setName("photo.jpg");
java.io.File filePath = new java.io.File("files/photo.jpg");
FileContent mediaContent = new FileContent("image/jpeg", filePath);
File file = driveFactory.getDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());

AdBlock WebView?

Is there a way to block ads in an Android WebView? I am building app that lets users browse web pages, but need to block ads. Its basically a custom browser, but I need to get rid of ads.
What is my best option?
Based on: https://github.com/adblockplus/adblockplusandroid
saw this:
https://gist.github.com/rjeschke/eb1bb76128c5e9a9e7bc
import java.io.File;
import java.util.regex.Pattern;
import org.adblockplus.android.ABPEngine;
import org.adblockplus.libadblockplus.FilterEngine.ContentType;
import android.content.Context;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class BlockingWebViewClient extends WebViewClient
{
private ABPEngine engine;
private static final Pattern RE_JS = Pattern.compile("\\.js$", Pattern.CASE_INSENSITIVE);
private static final Pattern RE_CSS = Pattern.compile("\\.css$", Pattern.CASE_INSENSITIVE);
private static final Pattern RE_IMAGE = Pattern.compile("\\.(?:gif|png|jpe?g|bmp|ico)$", Pattern.CASE_INSENSITIVE);
private static final Pattern RE_FONT = Pattern.compile("\\.(?:ttf|woff)$", Pattern.CASE_INSENSITIVE);
private static final Pattern RE_HTML = Pattern.compile("\\.html?$", Pattern.CASE_INSENSITIVE);
public void start(Context context)
{
final File basePath = context.getFilesDir();
this.engine = ABPEngine.create(context, ABPEngine.generateAppInfo(context),
basePath.getAbsolutePath());
// Additional steps may be required here, i.e. :
// - subscription selection or updating
// - maybe also setting other options (like AcceptableAds)
// It might also be a good idea to delay the first calls until
// everything is loaded, have a look at AndroidFilterChangeCallback
// and ABPEngine.create()
}
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
{
// Determine the content
ContentType contentType = null;
if (RE_JS.matcher(url).find())
{
contentType = ContentType.SCRIPT;
}
else if (RE_CSS.matcher(url).find())
{
contentType = ContentType.STYLESHEET;
}
else if (RE_IMAGE.matcher(url).find())
{
contentType = ContentType.IMAGE;
}
else if (RE_FONT.matcher(url).find())
{
contentType = ContentType.FONT;
}
else if (RE_HTML.matcher(url).find())
{
contentType = ContentType.SUBDOCUMENT;
}
else
{
contentType = ContentType.OTHER;
}
// Check if we should block ... we sadly do not have the referrer chain here,
// might also be hard to get as we do not have HTTP headers here
if (engine.matches(url, contentType, new String[0]))
{
// If we should block, return empty response which results in a 404
return new WebResourceResponse("text/plain", "UTF-8", null);
}
// Otherwise, continue by returning null
return null;
}
}
It is done already:
https://github.com/adblockplus/libadblockplus-android
You can put it at xml:
<org.adblockplus.libadblockplus.android.webview.AdblockWebView
android:id="#+id/main_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

Android: Add Digital Signature in xml Document Using DigitalSigner

I am trying to use below Class to append digital signature in xml request while posting the xml on http server. But As Android doesn't allow me to use the javax.xml.crypto.dsig. package I am unable to use it.
PN DigitalSigner is the 3rd party Class that they want us to use to sign the xml So my question is Is there any other way to sign the Xml Request without using javax.xml.crypto.dsig. if yes then how..?
thanks in advance
Here is the Class:
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
public class DigitalSigner {
private static final String MEC_TYPE = "DOM";
private static final String WHOLE_DOC_URI = "";
private static final String KEY_STORE_TYPE = "PKCS12";
private KeyStore.PrivateKeyEntry keyEntry;
/**
* Constructor
* #param keyStoreFile - Location of .p12 file
* #param keyStorePassword - Password of .p12 file
* #param alias - Alias of the certificate in .p12 file
*/
public DigitalSigner(InputStream keyStoreFile, char[] keyStorePassword, String alias) {
this.keyEntry = getKeyFromKeyStore(keyStoreFile, keyStorePassword, alias);
if (keyEntry == null) {
throw new RuntimeException("Key could not be read for digital signature. Please check value of signature "
+ "alias and signature password, ");
}
}
/**
* Method to digitally sign an XML document.
* #param xmlDocument - Input XML Document.
* #return Signed XML document
*/
public String signXML(String xmlDocument, boolean includeKeyInfo) {
Security.addProvider(new BouncyCastleProvider());
try {
// Parse the input XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document inputDocument = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(xmlDocument)));
// Sign the input XML's DOM document
Document signedDocument = sign(inputDocument, includeKeyInfo);
// Convert the signedDocument to XML String
StringWriter stringWriter = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(signedDocument), new StreamResult(stringWriter));
return stringWriter.getBuffer().toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error while digitally signing the XML document", e);
}
}
private Document sign(Document xmlDoc, boolean includeKeyInfo) throws Exception {
if (System.getenv("SKIP_DIGITAL_SIGNATURE") != null) {
return xmlDoc;
}
// Creating the XMLSignature factory.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance(MEC_TYPE);
// Creating the reference object, reading the whole document for
// signing.
Reference ref = fac.newReference(WHOLE_DOC_URI, fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null,
null);
// Create the SignedInfo.
SignedInfo sInfo = fac.newSignedInfo(
fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));
if (keyEntry == null) {
throw new RuntimeException(
"Key could not be read for digital signature.");
}
X509Certificate x509Cert = (X509Certificate) keyEntry.getCertificate();
KeyInfo kInfo = getKeyInfo(x509Cert, fac);
DOMSignContext dsc = new DOMSignContext(this.keyEntry.getPrivateKey(), xmlDoc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(sInfo, includeKeyInfo ? kInfo : null);
signature.sign(dsc);
Node node = dsc.getParent();
return node.getOwnerDocument();
}
private KeyInfo getKeyInfo(X509Certificate cert, XMLSignatureFactory fac) {
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
return kif.newKeyInfo(Collections.singletonList(xd));
}
private KeyStore.PrivateKeyEntry getKeyFromKeyStore(InputStream keyStoreFile, char[] keyStorePassword, String alias) {
// Load the KeyStore and get the signing key and certificate.
InputStream keyFileStream = null;
try {
KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
keyFileStream = keyStoreFile;
ks.load(keyFileStream, keyStorePassword);
KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) ks.getEntry(alias,
new KeyStore.PasswordProtection(keyStorePassword));
return entry;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (keyFileStream != null) {
try {
keyFileStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Try Apache Santuario:
Apache XML Security for Java: This library includes the standard JSR-105 (Java XML Digital Signature) API, a mature DOM-based implementation of both XML Signature and XML Encryption, as well as a more recent StAX-based (streaming) XML Signature and XML Encryption implementation.
So it should be compatible with the Java SE implementation of digital signature, both have been derived from JSR-105. The standalone development implementation has been removed from the Oracle site, unfortunately.

Categories

Resources