I am trying to send an S/MIME signed and encrypted mail to myself from Java Mail (bouncy castle 1.51) to my outlook.
I am able to send the mail fine but receiving is an issue as Outlook doesn't want to open the mail. The following is the error I get when trying to open:
Cannot open this item. Your Digital ID name cannot be found by the underlying security system.
The same mail (saved to a local file in eml format) is viewable fine with p7m Viewer, indicating that the P12 certificate has been installed correctly on my laptop. I have installed the same P12 file that I am using as Keystore in my Java Mail code.
Am I doing anything wrong? Is the issue at Outlook end? I am using Office 365 and wanted to add that p7m Viewer is also not able to open the smime.p7m that I download from the Outlook WebMail. The error I receive is:
The file is corrupted; Signature information might be missing.
Below is the Java code I am using to encrypt / send mail.
public class BCTest {
public static final String pkcs12Keystore = "C:/Development/Workspace/BouncyCastle_SecureMail/resources/cert/StartCom.p12";
public static final String ksPassword = "ksPassword";
public static final String sendFile = "C:/Development/Workspace/BouncyCastle_SecureMail/resources/hello.txt";
public static final String outputFile = "C:/Development/Workspace/BouncyCastle_SecureMail/output/Encrypted.eml";
public static final String message = "Hi There!!";
public static final String frAddress = "email#domain.com";
public static final String toAddress = "email#domain.com";
public static final String host = "outlook.office365.com";
public static final int port = 587;
public static final String userName = "email#domain.com";
public static final String password = "password";
public static void main(String[] args) {
send();
}
public static void send() {
try {
System.out.println("Setting Mailcap");
MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
CommandMap.setDefaultCommandMap(mailcap);
/* Add BC */
System.out.println("Setting Bouncy Castle as provider");
Security.addProvider(new BouncyCastleProvider());
/* Open the keystore */
System.out.println("Opening the keystore: " + pkcs12Keystore + " using password " + ksPassword);
KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
keystore.load(new FileInputStream(pkcs12Keystore), ksPassword.toCharArray());
// Find the first legit alias in the keystore and use it
System.out.println("Getting the keystore alias");
Enumeration<String> e = keystore.aliases();
String keyAlias = null;
while (e.hasMoreElements() && (keyAlias == null)) {
String alias = e.nextElement();
keyAlias = keystore.isKeyEntry(alias) ? alias : null;
}
if (keyAlias == null) {
throw new Exception("Can't find a private key!");
}
Certificate[] chain = keystore.getCertificateChain(keyAlias);
/* Get the private key to sign the message with */
System.out.println("Getting the private key");
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, ksPassword.toCharArray());
if (privateKey == null) {
throw new Exception("No private key for alias: " + keyAlias);
}
/* Create Email body */
System.out.println("Creating the Email body");
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message, "text/html");
/* Attach the file to encrypt */
System.out.println("Creating the attachment");
FileDataSource fds = new FileDataSource(sendFile);
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.setDataHandler(new DataHandler(fds));
attachPart.setFileName(fds.getName());
System.out.println("Adding body & attachment to mail");
MimeMultipart bodyMulti = new MimeMultipart();
bodyMulti.addBodyPart(messageBodyPart);
bodyMulti.addBodyPart(attachPart);
System.out.println("Setting mail properties");
Session session = Session.getDefaultInstance(System.getProperties());
MimeMessage body = new MimeMessage(session);
body.setFrom(new InternetAddress(frAddress));
body.setRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
body.setSentDate(new Date());
body.setSubject("Encrypted Mail");
body.setContent(bodyMulti, bodyMulti.getContentType());
body.saveChanges();
/* Create the SMIMESignedGenerator */
System.out.println("Creating the SMIMESignedGenerator");
SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
capabilities.addCapability(SMIMECapability.dES_CBC);
capabilities.addCapability(SMIMECapability.aES256_CBC);
System.out.println("Creating the ASN1EncodableVector");
ASN1EncodableVector attributes = new ASN1EncodableVector();
attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(new IssuerAndSerialNumber(new X500Name(((X509Certificate) chain[0])
.getIssuerDN().getName()), ((X509Certificate) chain[0]).getSerialNumber())));
attributes.add(new SMIMECapabilitiesAttribute(capabilities));
System.out.println("Adding certificate");
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add((X509Certificate) chain[0]);
SMIMESignedGenerator gen = new SMIMESignedGenerator("binary");
gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1withRSA", privateKey,
(X509Certificate) chain[0]));
gen.addCertificates(new JcaCertStore(certList));
MimeMultipart multiPart = gen.generate(body);
MimeMessage signedMessage = new MimeMessage(session);
System.out.println("Creating Mime Message");
#SuppressWarnings("unchecked")
Enumeration<String> headers = body.getAllHeaderLines();
while (headers.hasMoreElements()) {
signedMessage.addHeaderLine(headers.nextElement());
}
signedMessage.setContent(multiPart);
signedMessage.saveChanges();
/* Create the encrypter and encrypt the message */
System.out.println("Encrypting Mime Message");
SMIMEEnvelopedGenerator fact = new SMIMEEnvelopedGenerator();
fact.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator((X509Certificate) chain[0]).setProvider("BC"));
MimeBodyPart encryptedPart = fact.generate(signedMessage, new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40)
.setProvider("BC").build());
encryptedPart.setHeader("Content-Transfer-Encoding", "binary");
ByteArrayOutputStream out = new ByteArrayOutputStream();
encryptedPart.writeTo(out);
/* Create a new MimeMessage for the encrypted and signed content */
System.out.println("Setting mail server properties");
Properties props = new Properties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", port);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session smtpSession = Session.getInstance(props, new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
});
MimeMessage smtpMessage = new MimeMessage(smtpSession, new ByteArrayInputStream(out.toByteArray()));
smtpMessage.saveChanges();
/* Set all original MIME headers in the encrypted message */
#SuppressWarnings("unchecked")
Enumeration<String> orgHeaders = body.getAllHeaderLines();
while (orgHeaders.hasMoreElements()) {
String headerLine = (String) orgHeaders.nextElement();
/* Do not override content-* headers from the original message */
if (!Strings.toLowerCase(headerLine).startsWith("content-")) {
smtpMessage.addHeaderLine(headerLine);
}
}
System.out.println("Creating eml file as location: " + outputFile);
smtpMessage.writeTo(new FileOutputStream(outputFile));
System.out.println("Sending Mail");
Transport.send(smtpMessage);
System.out.println("Mail Sent");
} catch (SMIMEException ex) {
ex.getUnderlyingException().printStackTrace(System.err);
ex.printStackTrace(System.err);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
}
Plz help!!!
Regards
It sounds like you need to import your private key (in .p12 format) into Outlook's Personal trust store. Here is how to do that:
Import your personal certificate:
From the Tools menu, select Internet Options. Open the Content tab,
and click Certificates. In the Certificates window, select your
certificate and click Import. Work through the Certificate Import
Wizard to import your certificate file. When browsing for the correct
file, change the "Files of type" field from *.cer, *.crt to *.pfx,
*.p12. You will be prompted for the password used to encrypt the private key when the certificate was initially exported. Enter it. You
will want to select the Enable strong private key protection and Mark
this key as exportable radio buttons. You can select whatever storage
you want. It's easiest to put all the certificates in the Personal
store. Click Finish to exit the wizard. It will take a moment to
execute the import. A window pops up to say the application is
creating a protected item, and for you to select the security level.
Leaving it at medium (the default) is fine. Click OK. A window pops up
to say the import was successful. Click OK.
source: https://fermi.service-now.com/kb_view.do?sysparm_article=KB0010813
Related
*** Update: I have changed my approach as described in my answer to the question, due to which the original issue reported becomes moot. ***
I'm trying to develop a Nifi application that provides a WebSocket interface to Kakfa. I could not accomplish this using the standard Nifi components as I have tried below (it may not make sense but intuitively this is what I want to accomplish):
I have now created a custom Processor "ReadFromKafka" that I intend to use as shown in the image below. "ReadFromKafka" would use the same implementation as the standard "PutWebSocket" component but would read messages from a Kafka Topic and send as response to the WebSocket client.
I have provided a code snippet of the implementation below:
#SystemResourceConsideration(resource = SystemResource.MEMORY)
public class ReadFromKafka extends AbstractProcessor {
public static final PropertyDescriptor PROP_WS_SESSION_ID = new PropertyDescriptor.Builder()
.name("websocket-session-id")
.displayName("WebSocket Session Id")
.description("A NiFi Expression to retrieve the session id. If not specified, a message will be " +
"sent to all connected WebSocket peers for the WebSocket controller service endpoint.")
.required(true)
.addValidator(StandardValidators.NON_BLANK_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.defaultValue("${" + ATTR_WS_SESSION_ID + "}")
.build();
public static final PropertyDescriptor PROP_WS_CONTROLLER_SERVICE_ID = new PropertyDescriptor.Builder()
.name("websocket-controller-service-id")
.displayName("WebSocket ControllerService Id")
.description("A NiFi Expression to retrieve the id of a WebSocket ControllerService.")
.required(true)
.addValidator(StandardValidators.NON_BLANK_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.defaultValue("${" + ATTR_WS_CS_ID + "}")
.build();
public static final PropertyDescriptor PROP_WS_CONTROLLER_SERVICE_ENDPOINT = new PropertyDescriptor.Builder()
.name("websocket-endpoint-id")
.displayName("WebSocket Endpoint Id")
.description("A NiFi Expression to retrieve the endpoint id of a WebSocket ControllerService.")
.required(true)
.addValidator(StandardValidators.NON_BLANK_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.defaultValue("${" + ATTR_WS_ENDPOINT_ID + "}")
.build();
public static final PropertyDescriptor PROP_WS_MESSAGE_TYPE = new PropertyDescriptor.Builder()
.name("websocket-message-type")
.displayName("WebSocket Message Type")
.description("The type of message content: TEXT or BINARY")
.required(true)
.addValidator(StandardValidators.NON_BLANK_VALIDATOR)
.defaultValue(WebSocketMessage.Type.TEXT.toString())
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.build();
public static final Relationship REL_SUCCESS = new Relationship.Builder()
.name("success")
.description("FlowFiles that are sent successfully to the destination are transferred to this relationship.")
.build();
public static final Relationship REL_FAILURE = new Relationship.Builder()
.name("failure")
.description("FlowFiles that failed to send to the destination are transferred to this relationship.")
.build();
private static final List<PropertyDescriptor> descriptors;
private static final Set<Relationship> relationships;
static{
final List<PropertyDescriptor> innerDescriptorsList = new ArrayList<>();
innerDescriptorsList.add(PROP_WS_SESSION_ID);
innerDescriptorsList.add(PROP_WS_CONTROLLER_SERVICE_ID);
innerDescriptorsList.add(PROP_WS_CONTROLLER_SERVICE_ENDPOINT);
innerDescriptorsList.add(PROP_WS_MESSAGE_TYPE);
descriptors = Collections.unmodifiableList(innerDescriptorsList);
final Set<Relationship> innerRelationshipsSet = new HashSet<>();
innerRelationshipsSet.add(REL_SUCCESS);
innerRelationshipsSet.add(REL_FAILURE);
relationships = Collections.unmodifiableSet(innerRelationshipsSet);
}
#Override
public Set<Relationship> getRelationships() {
return relationships;
}
#Override
public final List<PropertyDescriptor> getSupportedPropertyDescriptors() {
return descriptors;
}
#Override
public void onTrigger(final ProcessContext context, final ProcessSession processSession) throws ProcessException {
final FlowFile flowfile = processSession.get();
if (flowfile == null) {
return;
}
final String sessionId = context.getProperty(PROP_WS_SESSION_ID)
.evaluateAttributeExpressions(flowfile).getValue();
final String webSocketServiceId = context.getProperty(PROP_WS_CONTROLLER_SERVICE_ID)
.evaluateAttributeExpressions(flowfile).getValue();
final String webSocketServiceEndpoint = context.getProperty(PROP_WS_CONTROLLER_SERVICE_ENDPOINT)
.evaluateAttributeExpressions(flowfile).getValue();
final String messageTypeStr = context.getProperty(PROP_WS_MESSAGE_TYPE)
.evaluateAttributeExpressions(flowfile).getValue();
final WebSocketMessage.Type messageType = WebSocketMessage.Type.valueOf(messageTypeStr);
if (StringUtils.isEmpty(sessionId)) {
getLogger().debug("Specific SessionID not specified. Message will be broadcast to all connected clients.");
}
if (StringUtils.isEmpty(webSocketServiceId)
|| StringUtils.isEmpty(webSocketServiceEndpoint)) {
transferToFailure(processSession, flowfile, "Required WebSocket attribute was not found.");
return;
}
final ControllerService controllerService = context.getControllerServiceLookup().getControllerService(webSocketServiceId);
if (controllerService == null) {
getLogger().debug("ControllerService is NULL");
transferToFailure(processSession, flowfile, "WebSocket ControllerService was not found.");
return;
} else if (!(controllerService instanceof WebSocketService)) {
getLogger().debug("ControllerService is not instance of WebSocketService");
transferToFailure(processSession, flowfile, "The ControllerService found was not a WebSocket ControllerService but a "
+ controllerService.getClass().getName());
return;
}
...
processSession.getProvenanceReporter().send(updatedFlowFile, transitUri.get(), transmissionMillis);
processSession.transfer(updatedFlowFile, REL_SUCCESS);
processSession.commit();
} catch (WebSocketConfigurationException|IllegalStateException|IOException e) {
// WebSocketConfigurationException: If the corresponding WebSocketGatewayProcessor has been stopped.
// IllegalStateException: Session is already closed or not found.
// IOException: other IO error.
getLogger().error("Failed to send message via WebSocket due to " + e, e);
transferToFailure(processSession, flowfile, e.toString());
}
}
private FlowFile transferToFailure(final ProcessSession processSession, FlowFile flowfile, final String value) {
flowfile = processSession.putAttribute(flowfile, ATTR_WS_FAILURE_DETAIL, value);
processSession.transfer(flowfile, REL_FAILURE);
return flowfile;
}
}
I have deployed the custom processor and when I connect to it using the Chrome "Simple Web Socket Client" I can see the following message in the logs:
ControllerService found was not a WebSocket ControllerService but a com.sun.proxy.$Proxy75
I'm using the exact same code as in PutWebSocket and can't figure out why it would behave any different when I use my custom Processor. I have configured "JettyWebSocketServer" as the ControllerService under "ListenWebSocket" as shown in the image below.
Additional exception details seen in the log are provided below:
java.lang.ClassCastException: class com.sun.proxy.$Proxy75 cannot be cast to class org.apache.nifi.websocket.WebSocketService (com.sun.proxy.$Proxy75 is in unnamed module of loader org.apache.nifi.nar.InstanceClassLoader #35c646b5; org.apache.nifi.websocket.WebSocketService is in unnamed module of loader org.apache.nifi.nar.NarClassLoader #361abd01)
I ended up modifying my flow to utilize out-of-box ListenWebSocket, PutWebSocket Processors, and a custom "FetchFromKafka" Processor that is a modified version of ConsumeKafkaRecord. With this I'm able to provide a WebSocket interface to Kafka. I have provided a screenshot of the updated flow below. More work needs to be done with the custom Processor to support multiple sessions.
my error is this:
org.apache.cxf.interceptor.Fault: Message part
{http://www.w3.org/2001/04/xmlenc#}EncryptedData was not recognized.
(Does it exist in service WSDL?)
Which is due to setting properties for decoding ecrypted data. My issue is that I am having problems how to do that with apache cxf (Timestamp and Signature works ok).
Here is my part of code:
public WSS4JStaxInInterceptor wss4JStaxInInterceptor() throws Exception {
WSSSecurityProperties inProperties = new WSSSecurityProperties();
//inProperties.addAction(WSSConstants.USERNAMETOKEN);
inProperties.addAction(WSSConstants.TIMESTAMP);
inProperties.addAction(WSSConstants.SIGNATURE);
inProperties.addAction(WSSConstants.ENCRYPTION);
inProperties.setEncryptionUser("xxx");
inProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("\"C:\\\\Users\\\\miha_\\\\OneDrive\\\\Dokumenti\\\\Job\\\\Lj\\\\Spring\\\\demo\\\\src\\\\main\\\\resources\\\\xxxx.jks"),"xxx".toCharArray());;
inProperties.setMustUnderstand(false);
inProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("\"C:\\\\Users\\\\miha_\\\\OneDrive\\\\Dokumenti\\\\Job\\\\Lj\\\\Spring\\\\demo\\\\src\\\\main\\\\resources\\\\xxxx.jks"),"xxx".toCharArray());
inProperties.setSignatureUser("cbd");
//inProperties.setSignatureVerificationCryptoProperties(wss4jInProperties());
//inProperties.setUsernameTokenPasswordType(WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST);
inProperties.setCallbackHandler(new ClientKeystorePasswordCallback());
WSS4JStaxInInterceptor wss4JStaxInInterceptor = new WSS4JStaxInInterceptor(inProperties);
return wss4JStaxInInterceptor;
}
So I define "loadDecryptionKeystore" in which I get keystore. But where do I define which certificate to take (with setEncryptionUser("xxx"); ?) and where password to access private key in certificate?
Should I define also something else, how ?
ps.: this is configuration for server part when receiving request
thank you
You define which certificate to take by calling setEncryptionUser.
The password for the private key should by supplied by the CallbackHandler that you define by calling setCallbackHandler. When the password for the private key will be needed, the framework will request it by calling the callback handler with an instance of WSPasswordCallback (see the documentation section about WSPasswordCallback identifiers for details).
A simple example of a callback handler:
/**
* #see ClientKeystorePasswordCallback
*/
public class ClientKeystorePasswordCallback implements CallbackHandler {
private Map<String, String> passwords =
new HashMap<String, String>();
public ClientKeystorePasswordCallback() {
passwords.put("myclientkey", "ckpass");
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
String pass = passwords.get(pc.getIdentifier());
if (pass != null) {
pc.setPassword(pass);
return;
}
}
}
}
I have a spring boot application running on heroku. I make use of websockets for sending messages to and from client and server for a specific user . I use spring boot's SimpMessagingTemplate.convertAndSendToUser to send and receive messages, which works fine for when a user needs get a message back from the server. I use Heroku session affinity which means that even if I scale up the number of sessions the user and websocket still share the same session.
My problem comes when I need a user to send a message to another user. It works fine if both users are sharing the session, but not if the message will not come through.
Is it possible to send a message from one user to another across different sessions using, SimpMessagingTemple? Or would I need to use a message broker, eg Redis.
I was looking into implementing sending a message using StringRedisTemplate but not sure how to send a message to a particular user.
private SimpMessagingTemplate messagingTemplate;
#Autowired
public MessageController(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
#MessageMapping("/secured/user-in")
public void sendToDevice(Message msg, #AuthenticationPrincipal User principal) throws Exception {
if (msg.getTo() != null) {
String email = msg.getTo();
Message out = new Message();
out.setMsg(msg.getMsg());
out.setFrom(msg.getFrom());
out.setTo(msg.getTo());
out.setSentTime(new Date());
out.setStatus(msg.getStatus());
messagingTemplate.convertAndSendToUser(email, "/secured/topic", out);
}
}
JS
function connect() {
var socket = new SockJS('/secured/user-in');
ST.stompClient = Stomp.over(socket);
var headers = {};
headers[ST.getHeader()] = ST.getToken();
ST.getStompClient().connect(headers, function (frame) {
retries = 1;
console.log('Connected: ' + frame);
ST.getStompClient().subscribe('/user/secured/topic', function (event){
var msg = JSON.parse(event.body);
showMessage(msg.msg);
});
});
}
UPDATE 1
I am guessing I could do something like this, as done here:
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload,
headerAccessor.getMessageHeaders());
But how could I get the session id of another user, I am using Redis to store session info: #EnableRedisHttpSession
I had my terminology a bit mixed up I was trying to send a message to another user on another dyno rather than session.
Ended up using redis sub/pub.
So when a message is receive by the controller it is published to redis, and the redis MessageListenerAdapter envokes the convertAndSendToUser method.
#MessageMapping("/secured/user-in")
public void sendToDevice(Message msg, #AuthenticationPrincipal User principal) throws Exception {
publishMessageToRedis(msg);
}
private void publishMessageToRedis(Message message) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String messageString = objectMapper.writeValueAsString(message);
stringRedisTemplate.convertAndSend("message", messageString);
}
redis config
#Bean
RedisMessageListenerContainer container( MessageListenerAdapter chatMessageListenerAdapter) throws URISyntaxException {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.addMessageListener(chatMessageListenerAdapter, new PatternTopic("message"));
return container;
}
#Bean("chatMessageListenerAdapter")
MessageListenerAdapter chatMessageListenerAdapter(RedisReceiver redisReceiver) {
return new MessageListenerAdapter(redisReceiver, "receiveChatMessage");
}
public class RedisReceiver {
private static final Logger LOG = LogManager.getLogger(RedisReceiver.class);
private final WebSocketMessageService webSocketMessageService;
#Autowired
public RedisReceiver(WebSocketMessageService webSocketMessageService) {
this.webSocketMessageService = webSocketMessageService;
}
// Invoked when message is publish to "chat" channel
public void receiveChatMessage(String messageStr) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Message message = objectMapper.readValue(messageStr, Message.class);
webSocketMessageService.sendChatMessage(message);
}
}
#Service
public class WebSocketMessageService {
private final SimpMessagingTemplate template;
private static final Logger LOG = LogManager.getLogger(WebSocketMessageService.class);
public WebSocketMessageService(SimpMessagingTemplate template) {
this.template = template;
}
public void sendChatMessage(Message message) {
template.convertAndSendToUser(message.getTo(), "/secured/topic", message);
}
}
Solution was based off this git repository
I have written an SNMP agent and registered a managed object (created/set a value of an MIB OID).
When I retrieve this value using SNMPv2c, the value is returned correctly - the PDU from ResponseEvent.getResponse has type=GET and the variable bindings have expected data - correct OID etc.
When I retrieve this value using SNMPv3 and user authentication, the value is not returned correctly - the PDU from ResponseEvent.getResponse has type=REPORT and the variable bindings have
a different OID from that in the request - from what I've read so far this indicates a config/authentication error.
Below is sample code (snippets) used for client & agent - please can you inform me how to create agent & client - where I'm going wrong?
// TestSNMPAgent:
public class TestSNMPAgent {
private OID sysDescr = new OID("1.3.6.1.2.1.1.1.0");
...
public static void main(String[] args) throws IOException {
TestSNMPAgent agent = new TestSNMPAgent();
agent.init("0.0.0.0/4071");
private void init(String agentIp) throws IOException {
agent = new SNMPAgent(agentIp);
agent.start();
agent.unregisterManagedObject(agent.getSnmpv2MIB());
agent.registerManagedObject(new MOScalar(oid,
MOAccessImpl.ACCESS_READ_WRITE,
getVariable(value),sysDescr,
"1")));
...
}
}
// SNMPAgent:
public class SNMPAgent extends BaseAgent {
...
#Override
protected void addUsmUser(USM arg0) {
UsmUser user = new UsmUser(new OctetString("SHADES"),
AuthSHA.ID,
new OctetString("SHADESAuthPassword"),
PrivDES.ID,
new OctetString("SHADESPrivPassword"));
}
#Override
protected void addViews(VacmMIB vacm) {
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHADES"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v3group"), new OctetString(),
SecurityModel.SECURITY_MODEL_USM,
SecurityLevel.NOAUTH_NOPRIV, VacmMIB.vacmExactMatch,
new OctetString("fullReadView"),
new OctetString("fullWriteView"),
new OctetString("fullNotifyView"),
StorageType.nonVolatile);
}
public void registerManagedObject(ManagedObject mo) {
try {
server.register(mo, null);
} catch (DuplicateRegistrationException ex) {
throw new RuntimeException(ex);
}
}
// TestSNMPMgr
public class TestSNMPMgr {
public static void main(String[] args) throws IOException {
TestSNMPMgr client = new TestSNMPMgr();
client.init();
}
public void init() {
SNMPMgr client = new SNMPMgr();
client.start();
// Get back Value which is set
String value = client.getAsString(new OID("1.3.6.1.2.1.1.1.0"));
}
}
// SNMPMgr
public class SNMPMgr {
Snmp snmp = null;
Address address = null;
public SNMPMgr()
{
address = "1.3.6.1.2.1.1.1.0";
}
/**
* Start the Snmp session. If you forget the listen() method you will not
* get any answers because the communication is asynchronous
* and the listen() method listens for answers.
* #throws IOException
*/
public void start() throws IOException {
address = GenericAddress.parse("udp:127.0.0.1/4701");
TransportMapping transport = new DefaultUdpTransportMapping();
snmp = new Snmp(transport);
USM usm = new USM(SecurityProtocols.getInstance(),
new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
transport.listen();
}
public void end() {
try {
snmp.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Method which takes a single OID and returns the response from the agent as a String.
* #param oid
* #return
* #throws IOException
*/
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[] { oid });
return event.getResponse().get(0).getVariable().toString();
}
public ResponseEvent get(OID oids[]) throws IOException {
PDU pdu = new ScopedPDU();
for (OID oid : oids) {
pdu.add(new VariableBinding(oid));
}
pdu.setType(PDU.GET);
// add user to the USM
snmp.getUSM().addUser(new OctetString("SHADES"),
new UsmUser(new OctetString("SHADES"),
AuthSHA.ID,
new OctetString("SHADESAuthPassword"),
PrivDES.ID,
new OctetString("SHADESPrivPassword")));
// send the PDU
ResponseEvent event = snmp.send(pdu, getTarget(), null);
if(event != null) {
return event;
}
throw new RuntimeException("GET timed out");
}
/**
* This method returns a Target, which contains information about
* where the data should be fetched and how.
* #return
*/
private UserTarget getTarget() {
UserTarget target = new UserTarget();
target.setAddress(address);
target.setRetries(1);
target.setTimeout(5000);
target.setVersion(SnmpConstants.version3);
target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
target.setSecurityName(new OctetString("SHADES"));
return target;
}
}
The OID in the Report PDU should tell you what is happening. Under typical circumstances there will be one or two (or one of two) request/report exchanges to establish initial SNMPv3 communications between manager and agent (or, rather, non-authoritative and authoritative engines, respectively).
The first is typically a usmStatUnknownEngineIDs report that allows the manager to discover the agent's Engine ID (needed for key localization/etc.) and will happen if you don't specify the proper Engine ID in the initial request. The second/other happens if using auth/noPriv or auth/priv level security, and that is usmStatsNotInTimeWindows, which is sent if the request doesn't specify Engine Boots/Engine Time values within proper range of the agent's values. These values prevent message replay attacks by making requests no longer valid if they fall out of the time window, and the manager typically doesn't know what they are until it receives them from the agent by way of a Report PDU.
After the manager has the proper Engine ID, Boots, and Time, and has localized keys to the Engine ID if necessary, then the normal request/response exchange can proceed as expected. Some SNMP APIs will take care of this exchange for you so you just send your request and get the eventual result after the exchange. It would seem that SNMP4j doesn't and you may have to handle it yourself if it's one of these reports.
If it's not one of these reports, then you likely have a mismatch in configuration.
This is my java code using this code I am trying to create event with room (room is added using resource Google Calendar API) event created success fully with room A. However when I check in Google Calendar and try see available room in that A room is available. I would expect it should not display or it should show with strike can any one please tell me the solution for this where am doing I am mistake is there permission issue please suggest me.
public class CalendarQuickstart {
private static final String APPLICATION_NAME = "API Quickstart";
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),
".credentials/calendar-java-quickstart");
private static FileDataStoreFactory DATA_STORE_FACTORY;
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static HttpTransport HTTP_TRANSPORT;
private static final List < String > SCOPES = Arrays.asList(CalendarScopes.CALENDAR);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
public static Credential authorize() throws IOException {
// Load client secrets.
/*InputStream in = CalendarQuickstart.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;*/
Credential credential = GoogleCredential.fromStream(CalendarQuickstart.class.getResourceAsStream("/client_secret.json"))
.createScoped(SCOPES);
return credential;
}
public static com.google.api.services.calendar.Calendar getCalendarService() throws IOException {
Credential credential = authorize();
return new com.google.api.services.calendar.Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME).build();
}
public static void createEvent() throws IOException {
Event event = new Event().setSummary("Google I/O 2015")
.setDescription("A chance to hear more about Google's developer products.");
DateTime startDateTime = new DateTime("2017-02-27T22:00:00+05:30");
EventDateTime start = new EventDateTime().setDateTime(startDateTime).setTimeZone("Asia/Kolkata");
event.setStart(start);
DateTime endDateTime = new DateTime("2017-02-27T23:00:00+05:30");
EventDateTime end = new EventDateTime().setDateTime(endDateTime).setTimeZone("Asia/Kolkata");
event.setEnd(end);
EventAttendee[] attendees = new EventAttendee[] {
new EventAttendee().setEmail("account#gmail.com"),
new EventAttendee().setEmail("anil#gmail.com"), new EventAttendee().
setEmail("company.com_35353134363037362d333130#resource.calendar.google.com").setResponseStatus("accepted")
};
event.setAttendees(Arrays.asList(attendees));
EventReminder[] reminderOverrides = new EventReminder[] {
new EventReminder().setMethod("email").setMinutes(24 * 60),
new EventReminder().setMethod("popup").setMinutes(10),
};
Event.Reminders reminders = new Event.Reminders().setUseDefault(false)
.setOverrides(Arrays.asList(reminderOverrides));
event.setReminders(reminders);
String calendarId = "primary";
event = getCalendarService().events().insert(calendarId, event).execute();
System.out.printf("Event created: %s\n", event.getId());
}
public static void updateEvent() throws IOException {
Event event = getCalendarService().events().get("primary", "3k90eohao76bk3vlgs8k5is6h0").execute();
event.setSummary("Appointment at Somewhere");
// Update the event
Event updatedEvent = getCalendarService().events().update("primary", event.getId(), event).execute();
System.out.println(updatedEvent.getUpdated());
}
public static void main(String[] args) throws IOException {
com.google.api.services.calendar.Calendar service = getCalendarService();
DateTime now = new DateTime(System.currentTimeMillis());
Events events = service.events().list("primary").setMaxResults(10).setTimeMin(now).setOrderBy("startTime")
.setSingleEvents(true).execute();
List < Event > items = events.getItems();
if (items.size() == 0) {
System.out.println("No upcoming events found.");
} else {
System.out.println("\nUpcoming events");
for (Event event: items) {
DateTime start = event.getStart().getDateTime();
if (start == null) {
start = event.getStart().getDate();
}
System.out.printf("%s (%s)\n", event.getSummary(), start);
}
}
createEvent();
}
You are using a service account. What you need to remember is that a service account is NOT you. Service accounts have their own Google calendar account Primary is its primary calendar.
String calendarId = "primary";
event = getCalendarService().events().insert(calendarId, event).execute();
This is going to add an event to the Service accounts primary Google Calendar which you can not see visually on the web.
Have you tried doing a events.list from your code this should show you the events on the service accounts google calendar.
If you want to be able to see this visually I suggest you create a calendar on your own personal Google Calendar account and grant your service account access to it by sharing it with the service accounts email address.
My blog post about service accounts
Hi All after long search from google i found solution .
Steps to create event google event.
Step1: Set following scopes to authorise api.
https://www.googleapis.com/auth/calendar.readonly
https://www.googleapis.com/auth/calendar
Step2: While authorizing asks for permission to manage and view calendar , uses has to allow it .
and which will generated authorization code.
Step3: Create access_token by generated authorization code
Step 4: Pass generated access_token to craete google event.
Java code to create google event
public static com.google.api.services.calendar.Calendar getCalendarService() {
GoogleCredential credential = new GoogleCredential().setAccessToken(access_token);
return new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();
}
these steps Work for me block room while creating Event using Google calendar api.
i have tried with another way using service account in that case we are able to create event but not able to block room .