I am trying to develop an SNMPv3 Trap Receiver using the WebNms AdventNet API.
If I use authentication and privacy options (MD5 + DES), I need to know the engineID of the Agent that sends the traps in
order to decrypt the trap content. How can I obtain this engineID dynamically (without hardcoding it in my application)?
I saw that it's possible to perform a discovery of the engineID
But for this to work I need to provide the port used by the Agent when sends the traps (and the agent is a real network element which uses random source ports).
The following code is working, but I hard-coded the engineID.
Is there a different way to decrypt the traps without hardcoding the engineID?
public class DragosApp2 implements SnmpClient{
public static void main(String[] args) throws SnmpException {
SnmpAPI api = new SnmpAPI();
SnmpEngineEntry snmpEntry = new SnmpEngineEntry("10.10.66.79");
SnmpEngineTable engineTable = api.getSnmpEngine();
engineTable.addEntry(snmpEntry);
SnmpSession session = new SnmpSession(api);
session.addSnmpClient(new DragosApp2());
UDPProtocolOptions ses_opt = new UDPProtocolOptions();
ses_opt.setLocalPort(162);
session.setProtocolOptions(ses_opt);
session.open();
byte[] engineID = gethexValue("0x80001f888026f9036957333c81"); // HOW can I replace this part??
USMUserEntry user = new USMUserEntry(new String("dragos3").getBytes(), engineID);
user.setAuthProtocol(USMUserEntry.MD5_AUTH);
user.setPrivProtocol(USMUserEntry.CBC_DES);
byte[] authKey = USMUtils.password_to_key(USMUserEntry.MD5_AUTH,
new String("12345678").getBytes(),
new String("12345678").getBytes().length,
engineID);
byte[] privKey = USMUtils.password_to_key(USMUserEntry.MD5_AUTH,
new String("12345678").getBytes(),
new String("12345678").getBytes().length,
engineID,
USMUserEntry.CBC_DES);
user.setAuthPassword(new String("12345678").getBytes());
user.setPrivPassword(new String("12345678").getBytes());
user.setAuthKey(authKey);
user.setPrivKey(privKey);
user.setSecurityLevel((byte)3);
user.setEngineEntry(snmpEntry);
USMUserTable uut = (USMUserTable)api.getSecurityProvider().getTable(3);
uut.addEntry(user);
}
}
Related
i want to create request xml-rpc struct in java, my code is like this
public String xmlprc() throws XmlRpcException, MalformedURLException{
ReqModelTest req = new ReqModelTest();
String test="";
Object paramsR = new Object();
Vector params = new Vector();
req.setvalue1("value1");
req.setvalue2("value2");
req.setvalue3("value3");
req.setvalue4("value4");
req.setvalue5("value5");
params.add(req);
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
config.setServerURL(new URL("myurl"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
paramsR = (Object)client.execute("mymethod", params);
} catch (MalformedURLException | XmlRpcException e) {
log.info(e);
}
log.info(paramsR.toString());
test = paramsR.toString();
return test;
}
but when i run it, it shows error org.apache.xmlrpc.XmlRpcException: Failed to generate request: Unsupported Java type: com.model.ReqModelTest. is there any way how to do it? Thank you very much
The most common error we have in these cases is not implementing Serializable interface.
The documentation tells us to follow these steps :
All primitive Java types are supported, including long, byte, short, and double.
Calendar objects are supported. In particular, timezone settings, and milliseconds may be sent.
DOM nodes, or JAXB objects, can be transmitted. So are objects implementing the java.io.Serializable interface.
Both server and client can operate in a streaming mode, which preserves resources much better than the default mode, which is based on large internal byte arrays.
Please check you are following these guidelines.
http://ws.apache.org/xmlrpc/
You need to create custom TypeFactory to handle your own data types.
Please see this link
I'm working on this project in which I'm using a Google-App-Engine backend connected to an Android app via Google-Cloud-Endpoints. For Google-Cloud-Datastore access I'm using Objectify and everything works fine.
Now I decided to add the functionality to upload images to Google-Cloud-Storage but I couldn't find a clear explanation on how to do this using the Google-Cloud-Endpoints setup.
I found the following explanation how to use Google-Cloud-Storage with Google-App-Engine:
https://cloud.google.com/appengine/docs/java/googlecloudstorageclient/app-engine-cloud-storage-sample
but instead of adding it to the Endpoints Api the article writes an additional servlet.
Furthermore I found this example of upload/download for Android:
github.com /thorrism/GoogleCloudExample
Sadly this is using the Google Cloud Storage API for direct access to the Google-Cloud-Storage and you need to add a P12-file to the asset folder, which seems unsecure.
My Google-App-Engine code looks like that:
#Api(
name = "example",
version = "v1",
scopes = { Constants.EMAIL_SCOPE },
clientIds = { Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID },
audiences = {Constants.ANDROID_AUDIENCE},
description = "API for the Example Backend application."
)
public class ExampleApi{
#ApiMethod(name = "doSomething", path = "dosomething", httpMethod = HttpMethod.POST)
public String doSomething(#Named("text") String text){
TestEntity test = new TestEntity(text);
ofy().save().entity(test).now();
return test;
}
After I uploaded it I generated the Endpoints Client Library and imported it into my android project.
Then I'm calling Endpoints from Android like explained here:
https://cloud.google.com/appengine/docs/java/endpoints/calling-from-android#creating_the_service_object
public static com.appspot.******.example.Example buildServiceHandler(Context context, String email) {
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(
context, AppConstants.AUDIENCE);
credential.setSelectedAccountName(email);
com.appspot.******.example.Example.Builder builder = new com.appspot.******.example.Example.Builder(
AppConstants.HTTP_TRANSPORT,
AppConstants.JSON_FACTORY, null);
builder.setApplicationName("example-server");
return builder.build();
}
sApiServiceHandler = buildServiceHandlerWithAuth(context,email);
And each Api-Method I call like this:
com.appspot.******.example.Example.DoSomething doSomething = sApiServiceHandler.doSomething(someString);
doSomething.execute();
All of this works fine, but only for storing/receiving Datastore Entities. How would I go about uploading/downloading files to Google Cloud Storage using the Google Cloud Endpoints setup?
Is it somehow possible to send a POST with my image data via Endpoints to the UploadServlet using the already build ServiceHandler ?
Is it possible to call a servlet from an Endpoints Method? How am I supposed to send the Post to the Servlet and how would I go about the authentication?
Any help or advice would be greatly appreciated!
There are different ways to do this, but the most recommended way is to use Signed URLs, so that your Android app can upload the file securely to Google Cloud Storage directly, without going through your Endpoints backend. The basic process is:
1) Create an Endpoints method that creates a new signed URL and returns it to the Android client. Signing the URL on the server still requires a P12 key but is stored on App Engine, not on the client, so is secure. Try to use a short expiration for the URL, for example no more than 5 minutes.
2) Have the Android client upload the file directly to the signed URL, as you would doing a normal HTTP PUT to the Cloud Storage XML API to upload a file (resumable uploads with the JSON API are also supported, but not covered here).
Your Endpoints method might look like this:
#ApiMethod(name = "getUploadUrl", path = "getuploadurl", httpMethod = HttpMethod.GET)
public MyApiResponse getUploadUrl(#Named("fileName") String fileName
#Named("contentType" String contentType)
{
String stringToSign
= "PUT\n" + contentType
+ "\n" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS + "\n"
+ YOUR_GCS_BUCKET + "/" + fileName;
// Load P12 key
FileInputStream fileInputStream = new FileInputStream(PATH_TO_P12_KEY);
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(fileInputStream, password);
PrivateKey key = keyStore.getKey(privatekey", YOUR_P12_KEY_PASSWORD);
// Get signature
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initSign(key);
signer.update(stringToSign.getBytes("UTF-8"));
byte[] rawSignature = signer.sign();
String signature = new String(Base64.encodeBase64(rawSignature, false), "UTF-8");
// Construct signed url
String url
= "http://storage.googleapis.com/" + YOUR_GCS_BUCKET + fileName
+ "?GoogleAccessId=" + P12_KEY_SERVICE_ACCOUNT_CLIENT_ID
+ "&Expires=" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS
+ "&Signature=" + URLEncoder.encode(signature, "UTF-8");
// Endpoints doesn't let you return 'String' directly
MyApiResponse response = new MyApiResponse();
response.setString(url);
return response;
}
On the Android side, you might use the method like this:
// Get the upload URL from the API
getUploadUrl = sApiServiceHandler.getUploadUrl(fileName, contentType);
MyApiResponse response = getUploadUrl.execute();
String uploadUrl = response.getString();
// Open connection to GCS
URL url = new URL(uploadUrl);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setDoOutput(true);
httpConnection.setRequestMethod("PUT");
httpConnection.setRequestProperty("Content-Type", contentType);
// Write file data
OutputStreamWriter out = new OutputStreamWriter(httpConnection.getOutputStream());
out.write(fileData);
out.flush();
// Get response, check status code etc.
InputStreamReader in = new InputStreamReader(httpConnection.getInputStream());
// ...
(Disclaimer: I'm just typing code freely into a text editor but not actually testing it, but it should be enough to give you a general idea.)
I would like to simply open an AMQP 1.0 connection with a specific max_frame_size using the Apache Qpid Proton client library. This is inside a testsuite, not a real world application.
The Java library seems more advanced than the C library and its various bindings for other languages, so I started to use the Java one. Unfortunately, I can't find a way to set this parameter, though there must be a way: there is this Transport class which offers to get or set max_frame_size.
I first tried with the Messenger API, then I played with the Engine API. I couldn't figure out how to access the transport instance. In the case of the Engine API, I see there is a Connection.getTransport() and tried that, but it's NULL at the time I call this function.
Here is my last test:
private void do_test_with_frame_size(int frame_size, int payload_size) {
Connection conn = Connection.Factory.create();
Transport transport = conn.getTransport();
transport.setMaxFrameSize(frame_size);
Session session = conn.session();
Sender sender = session.sender("sender");
conn.open();
session.open();
sender.open();
if (sender.getCredit() > 0) {
String uri = System.getProperty("broker_uri");
assertNotNull(uri);
String address = String.format("%s/fragmentation-%d-%d",
uri, frame_size, payload_size);
Message message = Proton.message();
message.setAddress(address);
message.setBody(new AmqpValue(new byte[payload_size]));
byte[] msgData = new byte[1024];
int length;
while(true) {
try {
length = message.encode(msgData, 0, msgData.length);
break;
} catch(BufferOverflowException e) {
msgData = new byte[msgData.length * 2];
}
}
byte[] tag = "0".getBytes();
Delivery delivery = sender.delivery(tag);
sender.send(msgData, 0, length);
delivery.settle();
sender.advance();
sender.close();
sender.getSession().close();
sender.getSession().getConnection().close();
}
}
I admit I have very limited knowledge of Java. Could you please confirm it is even possible to set this parameter and, if yes, tell me how to?
You need to create a Transport instance for the connection to use and then bind the transport to the connection instance. A created Connection does not have an implicit Transport bound to it which is why you get a null returned to you currently.
private final Transport protonTransport = Proton.transport();
private final Connection protonConnection = Proton.connection();
...
this.protonTransport.setMaxFrameSize(maxFrameSize);
this.protonTransport.setChannelMax(CHANNEL_MAX);
this.protonTransport.bind(this.protonConnection);
Is there any equivalent of TSerializer in the Thrift C# API.
I am trying to use thrift serialization and then push the serialized object into MQ, not using Thrift transport mechanism. On the other end I'll deserialize it to the actual message.
I can do it in Java but not in C#.
The Apache Thrift C# library doesn't have a TSerializer presently. However it does have a TMemoryBuffer (essentially a transport that reads/writes memory) which works perfectly for this kind of thing. Create a TMemoryBuffer, construct a protocol (like TBinaryProtocol) and then serialize your messages and send them as blobs from the TMemoryBuffer.
For example:
TMemoryBuffer trans = new TMemoryBuffer(); //Transport
TProtocol proto = new TCompactProtocol(trans); //Protocol
PNWF.Trade trade = new PNWF.Trade(initStuff); //Message type (thrift struct)
trade.Write(proto); //Serialize the message to memory
byte[] bytes = trans.GetBuffer(); //Get the serialized message bytes
//SendAMQPMsg(bytes); //Send them!
To receive the message you just do the reverse. TMemoryBuffer has a constructor you can use to set the received bytes to read from.
public TMemoryBuffer(byte[] buf);
Then you just call your struct Read() method on the read side I/O stack.
This isn't much more code (maybe less) than using the Java TSerializer helper and it is a bit more universal across Apache Thrift language libraries. You may find TMemoryBuffer is the way to go everywhere!
Credit due to the other answer on this page, and from here:
http://www.markhneedham.com/blog/2008/08/29/c-thrift-examples/
Rather than expecting everyone to take the explanations and write their own functions, here are two functions to serialize and deserialize generalized thrift objects in C#:
public static byte[] serialize(TBase obj)
{
var stream = new MemoryStream();
TProtocol tProtocol = new TBinaryProtocol(new TStreamTransport(stream, stream));
obj.Write(tProtocol);
return stream.ToArray();
}
public static T deserialize<T>(byte[] data) where T : TBase, new()
{
T result = new T();
var buffer = new TMemoryBuffer(data);
TProtocol tProtocol = new TBinaryProtocol(buffer);
result.Read(tProtocol);
return result;
}
There is an RPC framework that uses the standard thrift Protocol named "thrifty", and it is the same effect as using thrift IDL to define the service, that is, thrify can be compatible with code that uses thrift IDL, and it include serializer:
[ThriftStruct]
public class LogEntry
{
[ThriftConstructor]
public LogEntry([ThriftField(1)]String category, [ThriftField(2)]String message)
{
this.Category = category;
this.Message = message;
}
[ThriftField(1)]
public String Category { get; }
[ThriftField(2)]
public String Message { get; }
}
ThriftSerializer s = new ThriftSerializer(ThriftSerializer.SerializeProtocol.Binary);
byte[] s = s.Serialize<LogEntry>();
s.Deserialize<LogEntry>(s);
more detail: https://github.com/endink/Thrifty
I'm looking for a way to inspect the contents of a HttpServletResponse to sign them with a MD5 hash.
The pseudocode might look like this
process(Response response, Request request){
defaultProcessingFor(response,request);
dispatcher.handle(response,request);
// Here I want to read the contents of the Response object (now filled with data) to create a MD5 hash with them and add it to a header.
}
Is that possible?
Yes, that's possible. You need to decorate the response with help of HttpServletResponseWrapper wherein you replace the ServletOutputStream with a custom implementation which writes the bytes to both the MD5 digest and the "original" outputstream. Finally provide an accessor to obtain the final MD5 sum.
Update I just for fun played a bit round it, here's a kickoff example:
The response wrapper:
public class MD5ServletResponse extends HttpServletResponseWrapper {
private final MD5ServletOutputStream output;
private final PrintWriter writer;
public MD5ServletResponse(HttpServletResponse response) throws IOException {
super(response);
output = new MD5ServletOutputStream(response.getOutputStream());
writer = new PrintWriter(output, true);
}
public PrintWriter getWriter() throws IOException {
return writer;
}
public ServletOutputStream getOutputStream() throws IOException {
return output;
}
public byte[] getHash() {
return output.getHash();
}
}
The MD5 outputstream:
public class MD5ServletOutputStream extends ServletOutputStream {
private final ServletOutputStream output;
private final MessageDigest md5;
{
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new ExceptionInInitializerError(e);
}
}
public MD5ServletOutputStream(ServletOutputStream output) {
this.output = output;
}
public void write(int i) throws IOException {
byte[] b = { (byte) i };
md5.update(b);
output.write(b, 0, 1);
}
public byte[] getHash() {
return md5.digest();
}
}
How to use it:
// Wrap original response with it:
MD5ServletResponse md5response = new MD5ServletResponse(response);
// Now just use md5response instead or response, e.g.:
dispatcher.handle(request, md5response);
// Then get the hash, e.g.:
byte[] hash = md5response.getHash();
StringBuilder hashAsHexString = new StringBuilder(hash.length * 2);
for (byte b : hash) {
hashAsHexString.append(String.format("%02x", b));
}
System.out.println(hashAsHexString); // Example af28cb895a479397f12083d1419d34e7.
Technically, the term "signature" is reserved to, well, signatures, and hash functions do not compute those.
To ensure that data was not altered in transit, with a hash function, then you must have a secure out-of-band way of transmitting the hash value; adding the hash value within the HTTP headers will not do, because anybody able to alter the transmitted data may recompute the hash at will, and alter the HTTP headers as it sees fit.
With cryptography, you can "concentrate" that secure out-of-band transmission into a reusable key. If client and server have a shared secret value, unknown to the supposed attacker, then the acronym is MAC, as in "Message Authentication Code"; a usual MAC is HMAC.
In many practical situations, a MAC cannot be used, because a MAC requires a shared secret, and a secret which shared too many times is not really secret anymore. Every secret holder has the power to recompute MAC. If every client knows the secret, then basically it is not a secret and it is safe to assume that the attacker also knows it. Hence, you can go a step further and use digital signatures (real ones, those which use RSA, DSS, ECDSA...) in which the server uses a private key (which only the server knows) and the clients know only of the corresponding public key. Knowledge of the public key is enough to verify signatures, but not to produce new ones, and the private key cannot be recomputed from the public key (although they are mathematically linked to each other). However, implementing a digital signature and using it properly is much more difficult than it is usually assumed; your best bet is then to use an already debugged protocol, with existing implementations, and that protocol happens to be called "SSL".
The point here is that without SSL, chances are that whatever you do will not deter a determined attacker; it will just use CPU cycles and network bandwidth, and give you a warm fuzzy feeling.
What are you trying to do?
You might be better off looking at a standard message format and wrap the contents of your response in such a message, and sign that. OAuth comes to mind.
Also, if you enable SSL, the client can be sure that the contents of the response have not been tampered with.