I am following https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-bulk-identity-mgmt to do Bulk upload of Device Identities in Azure IoT Hub. All codes given here are in C# so I am converting it to JAVA equivalent.
Using Import devices example – bulk device provisioning I am getting following json-
{"id":"d3d78b0d-6c8c-4ef5-a321-91fbb6a4b7d1","importMode":"create","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"f8/UZcYbhPxnNdbSl2J+0Q==","secondaryKey":"lbq4Y4Z8qWmfUxAQjRsDjw=="}}}
{"id":"70bbe407-8d65-4f57-936f-ef402aa66d07","importMode":"create","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"9e7fDNIFbMu/NmOfxo/vGg==","secondaryKey":"nwFiKR4HV9KYHzkeyu8nLA=="}}}
To import the file from blob following function is called-
CompletableFuture<JobProperties> importJob = registryManager
.importDevicesAsync(inURI, outURI);
In the above code, we need to provide URI with SAS code, for that Get the container SAS URI equivalent code is below-
static String GetContainerSasUri(CloudBlobContainer container) {
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.setSharedAccessExpiryTime(new Date(new Date().getTime() + TimeUnit.DAYS.toMillis(1)));
sasConstraints.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE,
SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE));
BlobContainerPermissions permissions = new BlobContainerPermissions();
permissions.setPublicAccess(BlobContainerPublicAccessType.CONTAINER);
permissions.getSharedAccessPolicies().put("testpolicy", sasConstraints);
try {
container.uploadPermissions(permissions);
} catch (StorageException e1) {
e1.printStackTrace();
}
String sasContainerToken = null;
try {
sasContainerToken = container.generateSharedAccessSignature(sasConstraints, "testpolicy");
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (StorageException e) {
e.printStackTrace();
}
System.out.println("URI " + container.getUri() +"?"+ sasContainerToken);
return container.getUri() + "?" + sasContainerToken;
}
Now the problem is coming here. For the output container I am getting following error-
java.util.concurrent.ExecutionException: com.microsoft.azure.sdk.iot.service.exceptions.IotHubBadFormatException: Bad message format! ErrorCode:BlobContainerValidationError;Unauthorized to write to output blob container. Tracking ID:2dcb2efbf1e14e33ba60dc8415dc03c3-G:4-TimeStamp:11/08/2017 16:16:10
Please help me to know why I am getting Bad Message Format error? Is there a problem with the SAS key generating code or my blob container is not having Write permission?
are you using a service or Account-level SAS? The error thrown suggests the service isn't authorized or have the delegated permissions to write to the designated blob container. Check out the resource here on how to setup an account level SAS and how to delegate read, write and delete operations on blob containers. https://learn.microsoft.com/en-us/rest/api/storageservices/Delegating-Access-with-a-Shared-Access-Signature?redirectedfrom=MSDN "snipped content: "An account-level SAS, introduced with version 2015-04-05. The account SAS delegates access to resources in one or more of the storage services. All of the operations available via a service SAS are also available via an account SAS. Additionally, with the account SAS, you can delegate access to operations that apply to a given service, such as Get/Set Service Properties and Get Service Stats. You can also delegate access to read, write, and delete operations on blob containers, tables, queues, and file shares that are not permitted with a service SAS. See Constructing an Account SAS for more information about account SAS."
I was facing the same issue while using private storage account as import/output container.
It is working smooth after I started using public storage account.
Anyway, it should work even with private storage account. So, I have raised an issue. For more into, you may refer this link.
Related
I am creating an android app to record a user's activity using Google Maps SDK and the Google Play Services Location API. I am attempting to retrieve the user's elevation based on a given latitude and longitude. I originally used Location#getAltitude() but then realised that does not give the elevation above sea level.
I proceeded to use the open elevation API using the following query string:
String url = "https://api.open-elevation.com/api/v1/lookup?locations=" + latLng.latitude + "," + latLng.longitude;
However, that API appears to be much too slow in generating a response. I then found the Google Maps Elevation API which we can make a request using a URL also. However, we need to pass an API key and I do not want to pass this API key in the URL string and end up committing it to the remote repository.
In this repo (https://github.com/googlemaps/google-maps-services-java) I found the class:
/src/main/java/com/google/maps/ElevationApi.java which I thought I could use to avoid messing around with http requests.
In my gradle, I included this dependency:
implementation 'com.google.maps:google-maps-services:0.18.0'
At the moment, the code to retrieve the elevation is as follows:
ElevationApi.getByPoint(new GeoApiContext.Builder().apiKey(API_KEY).build(), latLng)
.setCallback(new PendingResult.Callback<ElevationResult>() {
#Override
public void onResult(ElevationResult result) {
consumer.doAction(result.elevation);
}
#Override
public void onFailure(Throwable e) {
e.printStackTrace();
}
});
What do I pass in for API_KEY here since I don't want to commit it to the repository? I have an api key defined in local.properties for maps, however, like so:
MAPS_API_KEY=<API_KEY_HERE>
Basically, my question is, can I define an API key in a properties file that is not committed to GitHub and then reference it in the code?
Thanks for any help.
Update:
I have managed to read the API key from local.properties using gradle but got an exception from the ElevationApi saying API 21+ expected, but was 30...strange. So I went back to the open-elevation API with the following Volley request:
/**
* Calculates elevation gain for the provided recording service
* #param recordingService the recording service to calculate elevation gain for
* #param response the handler to consume the elevation gain with
*/
public static void calculateElevationGain(RecordingService recordingService, ActionHandlerConsumer<Double> response) {
ArrayList<Location> locations = recordingService.getLocations();
JSONArray array = constructLocations(locations);
try {
if (array != null) {
RequestQueue requestQueue = Volley.newRequestQueue(recordingService);
String url = "https://api.open-elevation.com/api/v1/lookup";
JSONObject requestHeader = new JSONObject(); // TODO this seems very slow
requestHeader.put("locations", array);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, requestHeader,
response1 -> handleSuccessfulResponse(response1, response), RecordingUtils::handleErrorResponse);
request.setRetryPolicy(new DefaultRetryPolicy(500000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(request);
}
} catch (JSONException ex) {
ex.printStackTrace();
}
}
I had to set the timeout to a high number not sure how hight it should be because I was getting Volley timeout errors due to the slow response times.
Are there any other ways I can retrieve elevation about sea level?
Yeah, open-elevation.com has intermittent issues with timeouts and latency.
There are some alternatives listed on this GIS stack exchange question Seeking alternative to Google Maps Elevation API. I'm the developer of Open Topo Data which is the most-voted answer over there. You can host your own server with docker, and I also have a free public API which has pretty good latency and uptime.
There's also GPXZ as an alternative to the Google Elevation API with higher-quality data, but it requires an API key so would have the same issue as with Google Maps.
I advise a different direction: stay with the Google and the API key, but employ best practices regarding secrets and source repositories. Since you are dealing with an Android app and not a webapp your key can be somewhat safe inside your app binary (versus a key in a web deployed app is exposed).
Bets practices:
Do not commit the API key. The best to achieve this is to exclude the file which contains the key from the source control repo. That can simply be done with .gitignore. For example this Codelab has a file with the secret, but it has a dummy value and normally this file should be excluded from the source. It is only there because that is an educational code lab.
As a security measure take advantage of GitGuardian to scan your repos in case you'd accidentally push an API key. In such events you'd get a notification. As for me I forked that Geospatial API codelab and saw the key file was in the gitignore and I accidentally pushed a key.
In case you accidentally push a key in a commit it's not enough to reverse the commit and delete the file! Scavenger bots will still find the information in your git history. Rather immediately disable the key and generate another one.
If you are dealing with a webapp you can restrict the API key usage to your webapp's domain. Similarly you can restrict the key to specific Android app signatures (don't forget to add your developer environment's signature) too. This guarantees that even if someone steals the key they probably won't be able to use it.
I am working on golang version of fabcar smart contract while seeking to implement a Java-SDK API which enrolls an admin, registers a user and performs query-update value operations based on https://github.com/hyperledger/fabric-samples/tree/master/fabcar/java
I have successfully set up a 3 org-9 peers blockchain network, installed, instantiated and invoked chaincode on peers.
However, as i am working on implementing the relative API, i am only able to successfully query blockchain database, while getting a "Could not meet endorsement policy for chaincode mycc"
Please find below screenshot of relative error
Endorsement policy is "OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')".
Should registered user somehow get an Org1/Org2/Org3.member attribute? Any leads would be appreciated!
Like #Ikar Pohorský said, for me this got resolved after I used correct method name. Also, ensure that you delete 'wallet' folder in order to regenerate the user if your HLF n/w was recreated.
#Test
public void testMyMethodToBeInvoked() throws Exception {
deleteDirectory(".\\wallet");
EnrollAdmin.main(null);
RegisterUser.main(null);
// Load a file system based wallet for managing identities.
final Path walletPath = Paths.get("wallet");
final Wallet wallet = Wallet.createFileSystemWallet(walletPath);
// load a CCP
final Path networkConfigPath = Paths
.get("C:\\sw\\hlf146-2\\fabric-samples\\first-network\\connection-org1.yaml");
final Gateway.Builder builder = Gateway.createBuilder();
builder.identity(wallet, "user1").networkConfig(networkConfigPath).discovery(true);
// create a gateway connection
try (Gateway gateway = builder.connect()) {
final Network network = gateway.getNetwork("mychannel");
final Contract contract = network.getContract("mycc");
String myJSONString="{\"a\":\"b\"}";
byte[] result;
// Following did NOT work. Control goes directly to 'invoke' when 'submitTransaction' is done directly. 'invoke' need not be mentioned here.
// result = contract.submitTransaction("invoke", myJSONString);
// Following DID work. In chaincode (my chain code was Java) I had a method named 'myMethodToBeInvoked'. The chain code was written similar to https://github.com/hyperledger/fabric-samples/blob/release-1.4/chaincode/chaincode_example02/java/src/main/java/org/hyperledger/fabric/example/SimpleChaincode.java
result = contract.submitTransaction("myMethodToBeInvoked", my);
System.out.println(new String(result));
}
}
EDIT: Also, please remember that if your chaincode throws errorResponse, even then we can have this endorsement fail issue. So, check if your chain code is working without any issues.
I get an exception when trying to upload a file to Amazon S3 from my Java Spring application. The method is pretty simple:
private void productionFileSaver(String keyName, File f) throws InterruptedException {
String bucketName = "{my-bucket-name}";
TransferManager tm = new TransferManager(new ProfileCredentialsProvider());
// TransferManager processes all transfers asynchronously,
// so this call will return immediately.
Upload upload = tm.upload(
bucketName, keyName, new File("/mypath/myfile.png"));
try {
// Or you can block and wait for the upload to finish
upload.waitForCompletion();
System.out.println("Upload complete.");
} catch (AmazonClientException amazonClientException) {
System.out.println("Unable to upload file, upload was aborted.");
amazonClientException.printStackTrace();
}
}
It is basically the same that amazon provides here, and the same exception with the exactly same message ("profile file cannot be null") appears when trying this other version.
The problem is not related to the file not existing or being null (I have already checked in a thousand ways that the File argument recieved by TransferManager.upload method exists before calling it).
I cannot find any info about my exception message "profile file cannot be null". The first lines of the error log are the following:
com.amazonaws.AmazonClientException: Unable to complete transfer: profile file cannot be null
at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.unwrapExecutionException(AbstractTransfer.java:281)
at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.rethrowExecutionException(AbstractTransfer.java:265)
at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.waitForCompletion(AbstractTransfer.java:103)
at com.fullteaching.backend.file.FileController.productionFileSaver(FileController.java:371)
at com.fullteaching.backend.file.FileController.handlePictureUpload(FileController.java:247)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
My S3 policy allows getting and puttings objects for all kind of users.
What's happening?
ProfileCredentialsProvider() creates a new profile credentials provider that returns the AWS security credentials configured for the default profile.
So, if you haven't any configuration for default profile at ~/.aws/credentials, while trying to put object, it yields that error.
If you run your code on Lambda service, it will not provide this file. In that case, you also do not need to provide credentials. Just assign right IAM Role to your lambda function, then using default constructor should solve issue.
You may want to change TransferManager constructor according to your needs.
The solution was pretty simple: I was trying to implement this communication without an AmazonS3 bean for Spring.
This link will help with the configuration:
http://codeomitted.com/upload-file-to-s3-with-spring/
my code worked fine as below:
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(DefaultAWSCredentialsProviderChain.getInstance()).withRegion(clientRegion).build();
I did syncing from local couchbase server to my android and IOS application and it is working fine for mobile to server and server to mobile. Then i tried to insert document from JAVA Web application to local server and i succeed to do that. But the problem is that the document inserted by java web application is not syncing with both ios/android mobile applications. My java code to insert document to local server is as follows:
public class CouchBase {
public static void main(String args[]) {
Cluster cluster = CouchbaseCluster.create("127.0.0.1");
Bucket bucket = cluster.openBucket("test");
JsonObject user = JsonObject.empty()
.put("name", "amol")
.put("city", "mumbai");
JsonDocument doc = JsonDocument.create("102", user);
bucket.insert(doc);
System.out.println(doc.content().getString("name"));
}
}
In this code i have created one bucket and then i have created one json object holding required values and passing this object to the json document and finally inserting that document into bucket.
Now my mobile side code to create document:
Document document = database.getDocument(etId.getText().toString());
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", etName.getText().toString());
map.put("city", etCity.getText().toString());
try {
document.putProperties(map);
} catch (CouchbaseLiteException e) {
Log.e(TAG, "Error putting", e);
}
In this code i am simply creating one document and putting values in it.
My syncing code is as follows:
Replication pullReplication = database.createPullReplication(syncUrl);
Replication pushReplication = database.createPushReplication(syncUrl);
pullReplication.setContinuous(true);
pushReplication.setContinuous(true);
pullReplication.start();
pushReplication.start();
Where i am doing Bi-directional syncing.
I am not getting where i am wrong with java code.please help me to out of this problem
Sync gateway doesnt track document inserted through Couchbase-Server java sdk,Also It is not advised to directly insert the data in sync-gateway bucket through java-sdk, you can use bucket shadowing for that.
If you want to insert data through your web application you can make use of sync gateway rest api calls http://developer.couchbase.com/documentation/mobile/1.1.0/develop/references/sync-gateway/rest-api/index.html
At the time of this writing, it's not possible to use the Server SDKs on the bucket used by Sync Gateway. That's because when a new document revision is saved in a Sync Gateway database it goes through the Sync Function to route the documents to channels and grant users and roles access to channels. Some of that metadata is persisted under the _sync property in the document in Couchbase Server. The Server SDKs are not currently aware of the revision based system so it will update the field on the document without creating a new revision.
The recommended way to read/write the Sync Gateway data from a Java Web app is to use the Sync Gateway REST API.
I made a batch program which get some spread sheets and update them with Client Login method.
It had moved until 26 May.
But, it is no longer work now because authentication error happen.
I want to execute a batch program for SpreadSheets using the cron.
So, I tried to read the below pages and to migrate to OAuth2.0 method.
https://developers.google.com/api-client-library/java/google-api-java-client/client-login
https://developers.google.com/google-apps/spreadsheets/authorize
However, I couldn't understand how I use OAuth2.0 as a batch in Java code.
What I want to know is an authentication way that it doesn't need to operate manually when Spread Sheets API is run.
Please tell me a solution of this problem.
Thank you.
// current java source code
public static SpreadsheetService getService() {
SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration");
service.setProtocolVersion(SpreadsheetService.Versions.V3);
// get Username and Password from JSON file
String username = getValueJsonFile("Username", JSON_FILE);
String password = getValueJsonFile("Password", JSON_FILE);
try {
service.setUserCredentials(username, password);
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("Error code: " + e.getCodeName());
log.error(getMessage("WRONG_USER_PASS"));
}
return service;
}