peer not authenticated - Rally javatoolkit error - ssl

I have been using the rally javatoolkit for a while to add testcases, test results etc without any error. But all of a sudden it started throwing error as
" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated" . I have referred the pages "rally rest api java toolkit sslpeerunverifiedexception : peer not authenticated" , rally rest api java toolkit sslpeerunverifiedexception : peer not authenticated but they didn't help me. Can someone help me with what I am doing wrong. Also If i need to download a certificate please help me for windows system. Thanks in advance. my code is as below:
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.client.HttpClient;
import com.rallydev.rest.request.GetRequest;
import com.rallydev.rest.response.GetResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.scheme.Scheme;
public class ConnnectionTestWithHTTPClient {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String apiKey = "_abc123";
String applicationName = "Connnection Test With HTTPClient";
RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey);
restApi.setApplicationName(applicationName);
//restApi.setProxy(new URI("http://myproxy.mycompany.com"), "MyProxyUsername", "MyProxyPassword"); //SET PROXY SETTINS HERE
HttpClient client = restApi.getClient();
try {
SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() {
public boolean isTrusted(X509Certificate[] certificate, String authType)
throws CertificateException {
//trust all certs
return true;
}
}, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sf));
String workspaceRef = "/workspace/12345"; //USE VALID WORKSPACE OID
GetRequest getRequest = new GetRequest(workspaceRef);
GetResponse getResponse = restApi.get(getRequest);
System.out.println(getResponse.getObject());
} catch (Exception e) {
System.out.println(e);
} finally {
restApi.close();
}
}
}
Also adding to the issue, i found a different error when I changed the port from 443 to 8443. i get "java.io.IOException: HTTP/1.1 522 Origin Connection Time-out" when i use 8443.

For some reason when I uncomment the line //restApi.setProxy(new URI("http://myproxy.mycompany.com"), "MyProxyUsername", "MyProxyPassword"); with correct inputs, the error goes off.
For all those who need the inputs, please put in the following:
restApi.setProxy(new URI("http://rally1.rallydev.com"), "xyz#abc.com", "rallypassword");
so the working code is as below:
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.client.HttpClient;
import com.rallydev.rest.request.GetRequest;
import com.rallydev.rest.response.GetResponse;
public class ConnnectionTestWithHTTPClient {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String apiKey = "_apikey";
String applicationName = "Connnection Test With HTTPClient";
RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey);
restApi.setApplicationName(applicationName);
restApi.setProxy(new URI("http://rally1.rallydev.com"), "abc#abc.com", "rallypassword"); //YOUR PROXY SETTINGS HERE
HttpClient client = restApi.getClient();
try {
SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() {
public boolean isTrusted(X509Certificate[] certificate, String authType)
throws CertificateException {
//trust all certs
return true;
}
}, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sf));
String workspaceRef = "/workspace/1234";
GetRequest getRequest = new GetRequest(workspaceRef);
GetResponse getResponse = restApi.get(getRequest);
System.out.println(getResponse.getObject());
} catch (Exception e) {
System.out.println(e);
} finally {
restApi.close();
}
}
}

Related

Not able to invoke MobileFirst 8.0 PushNotification Rest Endpoint

I am trying to get the Authorization Token for sending push notification to the mobile app through MobileFirst Foundation 8.0 server. I have written the following code to send the request but I am not sure where I am messing things up, because the response which I am getting does not contains the token:
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.ClientResponse;
import org.apache.wink.client.Resource;
import org.apache.wink.client.RestClient;
public class SendPushNotification {
private String MFP_SERVER_URL = "1.2.3.4";
private int MFP_SERVER_PORT = 1234;
private static String URI_GET_TOKEN = "mfp/api/az/v1/token";
private static String URI_SEND_MESSAGE = "imfpush/v1/apps/my.app/messages";
private HttpClient client = new DefaultHttpClient();
private HttpHost host = new HttpHost(MFP_SERVER_URL,MFP_SERVER_PORT,"http");;
private HttpPost post;
public HttpResponse invokeRestfulService(String uri) throws ClientProtocolException, IOException{
List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();
parametersBody.add(new BasicNameValuePair("grant_type","client_credentials"));
parametersBody.add(new BasicNameValuePair("scope","access.sendMessage push.application.my.app messages.write"));
post = new HttpPost(uri);
post.setHeader("Authorization", "Basic Z292Lm1zLmFjY2Vzcy5wdXNoY2xpZW50OjJmaWxldWkudWF0");
post.setHeader("Content-type", "application/x-www-form-urlencoded");
post.setEntity(new UrlEncodedFormEntity(parametersBody, HTTP.UTF_8));
return client.execute(host,post);
}
public static void main(String[] args) throws ClientProtocolException, IOException{
SendPushNotification notification = new SendPushNotification();
HttpResponse httpResponse = notification.invokeRestfulService(URI_GET_TOKEN);
System.out.println(httpResponse);
notification.restClient();
}
public void restClient(){
ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);
Resource unprotectedResource = restClient.resource( "http://"+MFP_SERVER_URL + ":" + MFP_SERVER_PORT);
unprotectedResource.header( "Content-Type", "application/x-www-form-urlencoded");
unprotectedResource.header( "Authorization", "Basic Z292Lm1zLmFjY2Vzcy5wdXNoY2xpZW50OjJmaWxldWkudWF0");
unprotectedResource.attribute("grant_type", "client_credentials");
unprotectedResource.attribute("scope", "access.sendMessage push.application.gov.ms.tofileui messages.write");
ClientResponse clientResponse = unprotectedResource.contentType("application/x-www-form-urlencoded").accept("*/*").post(URI_GET_TOKEN);
System.out.println(clientResponse.getEntity(String.class));
}
}
I have tried 2 different ways of sending the request but the response which I am getting is 400-Bad Request.
Try changing String URI_GET_TOKEN = "mfp/api/az/v1/token" to String URI_GET_TOKEN = "/mfp/api/az/v1/token"

Unable to initialize AdaptersAPI Object in MobileFirst V8.0 adapter which is leading to NullPointerException

I am developing the adapter in MFP V8. Below is my code to validate username and password:
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import com.ibm.mfp.adapter.api.AdaptersAPI;
import com.ibm.mfp.adapter.api.ConfigurationAPI;
import com.ibm.mfp.security.checks.base.UserAuthenticationSecurityCheck;
import com.ibm.mfp.server.registration.external.model.AuthenticatedUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
#Api(value = "Sample Adapter Resource")
#Path("/resource")
public class UserValidationSecurityCheck extends UserAuthenticationSecurityCheck{
private String displayName;
private String errorMsg;
private HashMap<String,Object> adapterReponse = null;
#Context
AdaptersAPI adaptersAPI;
#Override
protected AuthenticatedUser createUser() {
return new AuthenticatedUser(displayName, displayName, this.getName(),adapterReponse);
}
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
if(credentials!=null && credentials.containsKey("username") && credentials.containsKey("password")){
if (credentials.get("username")!=null && credentials.get("password")!=null) {
String username = credentials.get("username").toString();
String password = credentials.get("password").toString();
if (username.equals(password)) {
JSONObject loginParams = new JSONObject();
loginParams.put("username", username);
loginParams.put("password", password);
HttpUriRequest httpUriRequest = adaptersAPI.createJavascriptAdapterRequest("LoginAndWeeklyCertAdapter1", "login", loginParams);
try {
HttpResponse httpResponse = adaptersAPI.executeAdapterRequest(httpUriRequest);
adapterReponse = adaptersAPI.getResponseAsJSON(httpResponse);
System.out.println(adapterReponse.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
} else {
errorMsg = "Wrong Credentials";
}
}
}
else{
errorMsg = "Credentials not set properly";
}
return false;
}
public boolean isLoggedIn(){
return getState().equals(STATE_SUCCESS);
}
public AuthenticatedUser getRegisteredUser() {
return registrationContext.getRegisteredUser();
}
#Override
protected Map<String, Object> createChallenge() {
Map<String, Object> challenge = new HashMap<String, Object>();
challenge.put("errorMsg", errorMsg);
challenge.put("remainingAttempts", getRemainingAttempts());
return challenge;
}
#ApiOperation(value = "Returns 'Hello from resource'", notes = "A basic example of a resource returning a constant string.")
#ApiResponses(value = { #ApiResponse(code = 200, message = "Hello message returned") })
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getResourceData() {
// log message to server log
logger.info("Logging info message...");
return "Hello from resource";
}
}
When I am submitting the challenge answer I am getting NullPointerException in following line:
HttpUriRequest httpUriRequest = adaptersAPI.createJavascriptAdapterRequest("LoginAndWeeklyCertAdapter1", "login");
because adaptersAPI is null. Do I have to do any extra configuration in order to make that work? How can I initialize AdaptersAPI object?
Note: The login method and the security check both are in same adapter.
Update
I investigated more of time into it and updated the code to given above and observed the following:
1. When validateCredentials() is getting called after submitting the challenge response then I am getting null value in AdapterAPI object.
2. Where as, when I am calling the getResourceData() using the mobilefirst swagger tool then I am getting an object of AdapterAPI.
We cannot inject the adapters API into a security check object(by design - not a bug). The only way we can go is to extract the logic from Adapter into a Java code, without using adapters API.

GDK Authentication mirror.accounts.insert.execute()

This is the test code for authentication and insert Account :
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Lists;
import com.google.api.services.mirror.Mirror;
import com.google.api.services.mirror.Mirror.Accounts.Insert;
import com.google.api.services.mirror.model.Account;
import com.google.api.services.mirror.model.AuthToken;
public class InsertAccountWithJava {
private static final String SERVICE_ACCOUNT_EMAIL ="540223414844-tqpuqtbv07klpuuk3q04qha0g88094uu#developer.gserviceaccount.com";
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH ="C:/Users/Yuan/Desktop/eyenotes-db176c40f51f.p12";
private static final String ACCOUNT_TYPE = "com.eyenotes";
private static final Collection<String> MIRROR_ACCOUNT_SCOPES =Arrays.asList("https://www.googleapis.com/auth/glass.thirdpartyauth");
private static String userToken = "6164da1732ea09b4";
private static String accountName="zhongmei";
private static String authTokenType ="eyenotes";
private static String authToken="myauthtoken";
public static void main(String[] args) {
try {
Mirror mirror = getMirrorService();
createAccount(mirror, userToken, accountName, authTokenType, authToken);
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public static Mirror getMirrorService() throws GeneralSecurityException, IOException, URISyntaxException {
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(MIRROR_ACCOUNT_SCOPES)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
Mirror service = new Mirror.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential).build();
return service;
}
public static void createAccount(Mirror mirror, String userToken, String accountName,
String authTokenType, String authToken) {
try {
Account account = new Account();
List<AuthToken> authTokens = Lists.newArrayList();
AuthToken authToken1 = new AuthToken().setType(authTokenType).setAuthToken(authToken);
authTokens.add(authToken1);
account.setAuthTokens(authTokens);
account.setPassword("zmyl123456");
Insert insert = mirror.accounts().insert(userToken, ACCOUNT_TYPE, accountName, account);
insert.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
============================================================================
I got the exception below:
============================================================================
Fabruary 06, 2015 1:42:21 pm com.google.api.client.googleapis.services.AbstractGoogleClient <init>
warning: Application name is not set. Call Builder#setApplicationName.
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
}, {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1049)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.ccfsz.service.InsertAccountWithJava.createAccount(InsertAccountWithJava.java:81)
at com.ccfsz.service.InsertAccountWithJava.main(InsertAccountWithJava.java:30)
=====================================================================================
Parameters explaination:
SERVICE_ACCOUNT_EMAIL:Generated when i create new Client ID in developer console.
SERVICE_ACCOUNT_PKCS12_FILE_PATH:Generated when i create new Client ID in developer console.
ACCOUNT_TYPE:I provided to google when submit my application.
userToken:I got from the authentication url provided to google.
accountName,authTokenType and authToken is arbitrary String.
2.Before i execute the code above ,do i need to do anything else?
3.I can get google authorization page through (https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https://www.googleapis.com/auth/glass.timeline+https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile&access_type=offline&approval_prompt=force&include_granted_scopes=true&client_id=540223414844-jjhqevuu0rhmoa3u6gkd05g7v29i89kk.apps.googleusercontent.com&redirect_uri=http://www.eyenotes.com/glass/login.php) using web application .how can i get this page and get permission using service account.
4.Who can give me any hint ? Sometimes,after execute test code above,i got nothing.in this case,according to their source code , this means i got a Http response code between 200 and 300, but i never get Accounts on my glass device which accountType equals "com.eyenotes".sometimes it return 400 with the excepiton above.
who have any idea,please tell me.I am very appreciate.
The userToken may not be the same every single time. Instead of hard-coding it to a String, I would get the token sent to your sign-in page during the authentication process.
Also, the error says you will need to call setApplicationName(String) on your Mirror object in the following code:
Mirror service = new Mirror.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential).build();
Refer to line 38 here.

Using OAuth retrieve access token without redirecting to a webpage

I had written a java program which uses client id and client secret for authentication. When i run my program it gives an url and when i go to that url it gives me access token. How can i programatically get the access token without using a browser?
My code:
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.Users;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class DirectoryCommandLine {
private static String CLIENT_ID = "YOUR_CLIENT_ID";
private static String CLIENT_SECRET = "YOUR_CLIENT_SECRET";
private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
public static void main(String[] args) throws IOException {
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_USER))
.setAccessType("online")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
System.out.println("Please open the following URL in your browser then type the authorization code:");
System.out.println(" " + url);
System.out.println("Enter authorization code:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String code = br.readLine();
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
// Create a new authorized API client
Directory service = new Directory.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("DirectoryCommandLine")
.build();
List<User> allUsers = new ArrayList<User>();
Directory.Users.List request = service.users().list().setCustomer("my_customer");
// Get all users
do {
try {
Users currentPage = request.execute();
allUsers.addAll(currentPage.getUsers());
request.setPageToken(currentPage.getNextPageToken());
} catch (IOException e) {
System.out.println("An error occurred: " + e);
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0 );
// Print all users
for (User currentUser : allUsers) {
System.out.println(currentUser.getPrimaryEmail());
}
}
}
You do need to use a browser to get user's authorization, but you only have to do it exactly once if you store your refresh token securely.
What's your scenario? You can use embedded browser in mobile, and get the authorization code automatically.

Safari Push Notifications

I would like to implement push notifications for my website (obviously only in compatible browser as Safari 7).
I have read the Apple documentation and I have successfully created my package containing my icon.iconset, my certificate.p12, manifest.json and a website.json.
Now I would like to ask the permission to the user when I first visit the website. If he allows it, I should send the package.
Everything is pretty clear but I don't know how to go on.
How do I create my push package out of my files? How do I precisely sign it? The package should be always the same so I could sign it on my mac and upload to my server only one package.
If you have experience with this technology, please let me know :)
I have successfully create push package to ask permission on safari web push notifications using REST API in java. Also I have follow steps which provide by Apple officials on there sites.
Please follow below steps to create push package.
Create your web push notification P12 certificate from your apple account.
Create your REST API using https for pushPackage which contain icon.iconset, your certificate.p12, manifest.json and a website.json. p12 certificate must be web push notification certificate.
How to create push package:- Please refer below java code. I have create push package using java servlet. which provide 2 web service end points.
v1/pushpackage/webpushID
v1/log
Servlet which process your push package request which send by safari push notification method
SafariPushPakageAPI.java
/*
Push Package REST API handler
*/
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import com.safari.Packager;
public class SafariPushPakageAPI extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
public static String ServerPath = null;
private static final String REQUEST_PERMISSION = "/v1/pushPackages/YOUR_WEB_PUSH_ID";
private static final String REQUEST_ERRORLOG = "/v1/log";
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doRequest(request, response);
}
// /v1/pushPackages/webpushID
// /v1/log
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doRequest(request, response);
}
private void doRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("===>> SAFARI PUSH NOTIFICATION REQUEST");
String path = request.getPathInfo();
System.out.println("PATH ===>> "+path);
if(path == null){
doRequestPermission(request, response);
}else if (path.equalsIgnoreCase(REQUEST_PERMISSION)){
doRequestPermission(request, response);
}else if (path.equalsIgnoreCase(REQUEST_ERRORLOG)){
doRequestShowErrorLog(request, response);
}else{
doRequestPermission(request, response);
}
}
private void doRequestPermission(HttpServletRequest request,HttpServletResponse response) {
try{
System.out.println("INSIDE REQUEST PERMISSION ==>>>");
System.out.println(IOUtils.toString(request.getReader()));
String authToken = StringUtils.isBlank(request.getParameter("token")) ? "UserTokenRT124DFGH" : StringUtils.trimToEmpty(request.getParameter("token"));
System.out.println("=>>>>>>>>>> USER TOKEN =>>>>>>>>>> "+authToken);
#SuppressWarnings("deprecation")
String packagePath =request.getRealPath("pushPackage.raw/icon.iconset/"); // LOCATION WHERE YOUR PUSH PACKAGE FOLDER CONTAIN LOGOS AND website.json file
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=\"pushpackage.zip\"");
OutputStream out = response.getOutputStream();
out.write(Packager.createPackageFile(authToken,packagePath));
response.flushBuffer();
}catch(IOException ioe){
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void doRequestShowErrorLog(HttpServletRequest request,HttpServletResponse response) {
try{
System.out.println("ERROR LOG STARTED");
System.out.println(IOUtils.toString(request.getReader()));
System.out.println("END");
}catch(Exception e){
e.printStackTrace();
}
}
}
Packager.java
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
/**
*
* #author Ritesh
*/
public class Packager {
final static String CERTIFICATE_PATH="PATH TO YOUR 12 CERTIFICATE";
final static String CERTIFICATE_PASS="PASSWORD";
static String getJSON(String authenticationToken) throws Exception {
JSONObject obj = new JSONObject();
obj.put("websiteName", "WEB SITE NAME");
obj.put("websitePushID", "WEB PUSH ID");
obj.put("allowedDomains", new JSONArray());
obj.getJSONArray("allowedDomains").put("https://TEST.EXAMPLE.net");//LIST OF DOMAINS ALLOW
obj.put("urlFormatString", "https://TEST.EXAMPLE.net/%#");
obj.put("authenticationToken", authenticationToken);
obj.put("webServiceURL", "https://API.EXAMPLE.COM");//callback URL WITHOUT WEB SERVICE ENDPOINT NAME
return obj.toString();
}
public static byte[] createPackageFile(String authenticationToken, String path) throws Exception {
System.out.println("packaging safari file with token: " + authenticationToken);
ZipHandler zip = new ZipHandler();
File dir = new File(path);
for (File file : dir.listFiles()) {
InputStream is = new FileInputStream(file);
byte[] bytes = IOUtils.toByteArray(is);
zip.addFile("icon.iconset", file.getName(),bytes );
}
zip.addFile("", "website.json", getJSON(authenticationToken).getBytes());
byte[] manifest = zip.manifest();
zip.addFile("", "manifest.json", manifest);
zip.addFile("", "signature", sign(manifest));
return zip.getBytes();
}
static byte[] sign(byte bytesToSign[]) throws Exception {
return new PKCS7Signer().sign(CERTIFICATE_PATH,CERTIFICATE_PASS, bytesToSign);
}
/**
* Servlet handler , should listen on the callback URL (as in webServiceURL)
* #param requestPath
* #param req
* #param servletRequest
* #param servletResponse
* #throws Exception
*/
public static void main(String[] args) throws Exception {
Packager.createPackageFile("SafriNotifcation","");
}
}
PKCS7Signer.java which create your signature file.
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
public final class PKCS7Signer {
static {
try{
Security.addProvider(new BouncyCastleProvider());
}catch(Exception e){
e.printStackTrace();
}
}
private KeyStore getKeystore(String storeLocation, String storePasswd) throws Exception {
if (storeLocation == null) {
System.out.println("Could not find store file (.p12)");
return null;
}
// First load the keystore object by providing the p12 file path
KeyStore clientStore = KeyStore.getInstance("PKCS12");
// replace testPass with the p12 password/pin
clientStore.load(new FileInputStream(storeLocation), storePasswd.toCharArray());
return clientStore;
}
private X509CertificateHolder getCert(KeyStore keystore, String alias) throws Exception {
java.security.cert.Certificate c = keystore.getCertificate(alias);
return new X509CertificateHolder(c.getEncoded());
}
private PrivateKey getPrivateKey(KeyStore keystore, String alias, String storePasswd) throws Exception {
return (PrivateKey) keystore.getKey(alias, storePasswd.toCharArray());
}
public byte[] sign(String storeLocation, String storePasswd, byte[] dataToSign) throws Exception {
KeyStore clientStore = getKeystore(storeLocation, storePasswd);
if (clientStore == null) {
return null;
}
Enumeration aliases = clientStore.aliases();
String alias = "";
while (aliases.hasMoreElements()) {
alias = (String) aliases.nextElement();
if (clientStore.isKeyEntry(alias)) {
break;
}
}
CMSTypedData msg = new CMSProcessableByteArray(dataToSign); // Data to sign
X509CertificateHolder x509Certificate = getCert(clientStore, alias);
List certList = new ArrayList();
certList.add(x509Certificate); // Adding the X509 Certificate
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
// Initializing the the BC's Signer
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(
getPrivateKey(clientStore, alias, storePasswd));
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder()
.setProvider("BC").build()).build(sha1Signer, x509Certificate));
// adding the certificate
gen.addCertificates(certs);
// Getting the signed data
CMSSignedData sigData = gen.generate(msg, false);
return sigData.getEncoded();
}
}
please note used latest bouncy castle jars for create signature file
bcprov-jdk15on-157.jar
bcpkix-jdk15on-157.jar
Write your javascript on your client side page.it contains simple java script to get permissions.
///
// For safari
var domain="YOUR WEB PUSH ID";
function safariIniti() {
var pResult = window.safari.pushNotification.permission(domain);
if(pResult.permission === 'default') {
//request permission
requestPermissions();
} else if (pResult.permission === 'granted') {
console.log("Permission for " + domain + " is " + pResult.permission);
var token = pResult.deviceToken;
// Show subscription for debug
console.log('Subscription details:'+token);
} else if(pResult.permission === 'denied') {
console.log("Permission for " + domain + " is " + pResult.permission);
}
}
function getToken(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and # (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
return (idstr);
}
function requestPermissions() {
var tokenVal = getToken();
window.safari.pushNotification.requestPermission('WEb service url without end points',domain,{token:tokenVal},
function(subscription) {
console.log(subscription.permission);
console.log("PERMISSION ====>> "+subscription.permission);
if(subscription.permission === 'granted') {
//TODO
}
else if(subscription.permission === 'denied') {
// TODO:
}
});
}
Apple provides a php file that you can use to create your push package including the signature. https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NotificationProgrammingGuideForWebsites/CompanionFile.zip
Alternatively, you can use the push_package gem, https://github.com/SymmetricInfinity/push_package, which we developed when implementing safari push notifications for zeropush.com. More details are available at https://zeropush.com/blog/implementing-safari-push-notifications-in-osx-mavericks.
Follow this apple documentation and github repo, they include sufficient information required to create a safari push notifications.