In the below code snippet I declare a username and passqord for the subscription.
private final String userName = "user_1";
private final char[] password = "pass".toCharArray();
....
....
final MqttAndroidClient client_1 = new MqttAndroidClient(getApplicationContext(), serverURI,
clientID, persistenceDataDir, Ack.AUTO_ACK);
MqttConnectOptions opts = new MqttConnectOptions();
opts.setCleanSession(false);
opts.setWill(WILL_TOPIC, WILL_MSG.getBytes(), QoS, false);
opts.setKeepAliveInterval(keepAliveInterval);
opts.setUserName(userName);
opts.setPassword(password);
I started the connection from the App with clean session = false and client ID = 1 without passwoed and username Provided, and I kept publishing (from the Pc to the broker) values of a topic I have subscribed to (from the App to the Broker.
Later in the subscribe message I set a pasword and username in my connection options, and did not specify the username and password to the publish message, and re-run the p. what happens is, I recieved the updated published values of the topic i am subsribed to.
After that, in the publish i specified a wrong username and password and subscriped to the same topic, and when i run the App, i receive the values normaly.
I am using the password and username wrongly?
To Note: I have tried the same procedure with different clientID and i receive the published values even with wrong password specified.
You need to set up a acl file and a password file in order to make usernames and passwords to control access to topics.
Please read the mosqitto.conf and mosquitto_passwd man pages for details of the format of both these files
http://mosquitto.org/man/mosquitto-conf-5.html
http://mosquitto.org/man/mosquitto_passwd-1.html
Related
I am integrating a Smart on FHIR app that will be launched from within an EHR. When the user clicks a button to launch the app, we set a GUID and the current Patient ID to a database record on our FHIR server. The assumption being that given the 'Launch' scope, the OAuth server will call the appropriate API to retrieve the Patient ID given that the GUID is included in the url params.
The call to auth looks like this:
_clientID = {the unique client ID registered to our auth server}
_redirectURL = {redirect back to auth for eventual token request}
launch={the GUID value generated at start of the session and paired with the Patient ID}
_scopes = "launch patient/*.* openid profile"
state = {some opaque value}
aud = {the base URL for our FHIR server}
string url = $"{authorizeURL}?response_type=code&client_id={_clientID}&" +
$"redirect_uri={_redirectURL}&" +
$"launch={launch}&" +
$"scope={HttpUtility.UrlEncode(_scopes)}&" +
$"state={state}&" +
$"aud=https://xxx-smart.xxxxxxxxx.com";
All of this works and I end up with a json response that includes the id_token, access_token, expires_in, token_type('Bearer'). But, no 'patient'.
My assumption was that the OAuth server would call the scope 'launch/patient' on our FHIR server but no such call is being made. In fact, I created a few endpoints just for the purpose of logging and NONE of them are being called.
Here is an example of one of my FHIR Server test/log endpoints (I created few with 1 to 4 parameters):
[AllowAnonymous]
[HttpGet("{functionName}/{id}")]
public string GetPatientData3(string functionName, string id)
{
TelemetryClient telemetry = new();
telemetry.TrackEvent($"FHIR SVR GetPatientData3 {functionName} {id}");
string configJson = "0009998888";
return configJson;
}
How do I set this 'patient' context properly?
How does the OAuth server retrieve this context so I can have that patient ID appear in the json response from the ~/token call?
Further Notes:
The contents of the openid-configuration:
{"token_endpoint":
"https://aadproxy.azurewebsites.net/xxx/oauth2/v2.0/token",
"token_endpoint_auth_methods_supported":
["client_secret_post","private_key_jwt","client_secret_basic"],
"jwks_uri":
"https://login.microsoftonline.com/xxx/discovery/v2.0/keys",
"response_modes_supported": ["query","fragment","form_post"],
"subject_types_supported": ["pairwise"],
"id_token_signing_alg_values_supported": ["RS256"],
"response_types_supported":["code","id_token","code
id_token","id_token token"],
"scopes_supported":["openid","profile","email","offline_access"],
"issuer": "https://login.microsoftonline.com/xxx/v2.0",
"request_uri_parameter_supported":false,
"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo",
"authorization_endpoint":
"https://aadproxy.azurewebsites.net/xxx/oauth2/v2.0/authorize",
"device_authorization_endpoint":
"https://login.microsoftonline.com/xxx/oauth2/v2.0/devicecode",
"http_logout_supported":true,
"frontchannel_logout_supported":true,
"end_session_endpoint":
"https://login.microsoftonline.com/xxx/oauth2/v2.0/logout",
"claims_supported":
["sub","iss","cloud_instance_name","cloud_instance_host_name",
"cloud_graph_host_name","msgraph_host","aud","exp","iat",
"auth_time","acr","nonce","preferred_username",
"name","tid","ver","at_hash","c_hash","email"],
"kerberos_endpoint":
"https://login.microsoftonline.com/xxx/kerberos",
"tenant_region_scope":"NA",
"cloud_instance_name":"microsoftonline.com",
"cloud_graph_host_name":"graph.windows.net",
"msgraph_host":"graph.microsoft.com",
"rbac_url":"https://pas.windows.net"}
So, I notice that the 'patient/.' and the 'launch' scope among a whole host of others that I have are not supported according to my openid config. The only supported ones are "openid","profile","email", "offline_access".
In Azure AD, 'App Registration' > 'Expose an API' I have a list of at least 15 scopes entered there. In 'API' permissions they are all listed there as well.
One other thing to note, AzureAD does not handle scopes with a forward slash. So, launch/patient has to be entered as launch-patient. We also had to implement a proxy server to capture the ~/oauth2/v2.0/authorize request and modify the scope parameter entries to reflect this before passing on the request to the actual server.
I guess the pertinent question now is: How do the scopes that I have entered manually get supported?
I'm trying to configure Oauth authorization on websphere 8.5.5.16. I added interceptor with issuerIdentifier parameter = https://company.com/abc I next step I added trust external realm: https://company.com/abc And when I try to start service in my app (IBM BPM) I getting an error: NullPointer Exception. Please look at the logs on how the user is created:
Principal: https://company.com/abc/login_user
Public Credential: com.ibm.ws.security.auth.WSCredentialImpl#ebc4e0d2
Private Credential: {setLtpaCookie=false, com.ibm.wsspi.security.cred.securityName=login_user, com.ibm.wsspi.security.cred.uniqueId=user:https://company.com/abc/login_user, token_type=, access_token=xxx, id_token=, com.ibm.wsspi.security.cred.realm=https://company.com/abc, com.ibm.wsspi.security.cred.groups=[], refresh_token=, JsonWebToken=JsonWebToken:{"aud":"0000","iss":"https://company.com/abc","iat":122,"nbf":123,"exp":232,"auth_time":222,"nonce":"aaa","sub":"ddddd/fffff","upn":"login_user","unique_name":"domain\\login_user","pwd_url":"https://company.com/abc/portal/updatepassword/","pwd_exp":"4545","sid":"S-1-5-21-66-117609710","authorities":["Group_1, Group_2"],"given_name":"Name","family_name":"Surname","apptype":"Public","appid":"0000","authmethod":"http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows","ver":"1.0","scp":"openid"}}
Private Credential: com.ibm.ws.security.token.SingleSignonTokenImpl#347c9d2b
Private Credential: com.ibm.ws.security.token.AuthenticationTokenImpl#718ea698
Private Credential: com.ibm.ws.security.token.AuthorizationTokenImpl#27e8a5bb
00000187 UserOrgModule 1 com.lombardisoftware.userorg.UserOrgModule getIdFromPrincipalName getIdFromPrincipalName() user=/company.com/abc/login_user, id=null
user = /company.com/abc/login_user not: login_user Why? Please help.
From message "00000187 UserOrgModule", I can tell your BPM application can not help realm name that contains '/' character. You can resolve the problem with following steps:
In your TAI properties, add useRealm property, and give an unique and meaningful value as realm, for example,
provider_.useRealm=abc123
Add "abc123" as trusted realm. This value matches value you define in step 1.
If you assign roles to users unique id, you need reassign roles again with unique id build from this new realm.
Thanks. I did exactly as you wrote.
I added in my interceptor config: provider_1.useRealm=myrealm
I added trusted realm in Global security > Federated repositories > Trusted authentication realms - inbound (Name = myrealm, Trusted).
I restarted server.
Nothing has changed. I still see: user=/company.com/abc/login_user, id=null because in JWT token, in iss field I have value: 'https://company.com/abc' and unfortunately I cannot change this
I am using Dart mailer in Flutter and there is a comment that says:
How you use and store passwords is up to you. Beware of storing passwords in plain.
Is there any way to hash the password? How can I avoid storing it in plain text?
It is generally not a good idea to store passwords in plain text anywhere. The way you handle passwords, though, depends on the platform.
Flutter
The flutter_secure_storage package uses Keychain on iOS and KeyStore on Android to store passwords (or tokens).
// Create storage
final storage = FlutterSecureStorage();
// Read secret
String value = await storage.read(key: key);
// Write secret
await storage.write(key: key, value: value);
Note that for Android the min API is 18.
Dart Server
If you are making a server, it is even more important not to store the user passwords in plain text. If the server is compromised, the attacker would have access to all of the passwords, and many users use the same password on multiple accounts.
It would be best to hand the authentication over to Google or Facebook or some other trusted third party by using OAuth2. However, if you are doing your own authorization, you should hash the passwords with a salt and save the hash, not the password itself. This makes it more difficult for an attacker to get the user passwords in case the server is compromised.
A basic implementation (but see comment below) could use the crypto package by the Dart Team.
// import 'package:crypto/crypto.dart';
// import 'dart:convert';
var password = 'password123';
var salt = 'UVocjgjgXg8P7zIsC93kKlRU8sPbTBhsAMFLnLUPDRYFIWAk';
var saltedPassword = salt + password;
var bytes = utf8.encode(saltedPassword);
var hash = sha256.convert(bytes);
Save the salt and the hash. Discard the password. Use a different salt for every user.
To make brute forcing the hashes more difficult, you can also check out the dbcrypt package.
If you want to hash
Use the password_hash package. Their example code is very easy to use:
var generator = new PBKDF2();
var salt = Salt.generateAsBase64String();
var hash = generator.generateKey("mytopsecretpassword", salt, 1000, 32);
Store both the hash and the salt, and you can verify someone else's password attempt by running the generator.generateKey function using their password and the saved salt.
What you actually want
If you're trying to automatically login, you of course need the original password, not a hash. You have a couple options
If the device that will have your app installed is safe, as in it is some company-owned device that has to be logged into by an employee, then have it in plaintext. It doesn't matter. As any company's security policy should be, you must make sure that hard drives are wiped before disposing of electronics (And make sure that no one can stroll in and take the iPad or whatever it is).
If unknown people outside of your organization will be installing your app, you will have to have them login and use their email, or have an API open that will send emails on their behalf (To prevent spamming from your email). The app would sent a POST to that API to send an email. If you had the plaintext password in the application, they could find it on their device, and abuse it.
This response comes late, but here is my approach to storing and using a password for sending emails to recipients using mailer in Flutter. I hope it helps anyone facing this issue.
First I downloaded the crypton package. Then I created a separate dart file where I handle everything related to sending mails, I called it mailer. In this file is where I specify the password, encrypts it using crypton, and use send the email using the decrypted password.
Below is the code of my mailer.dart file:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mailer/mailer.dart';
import 'package:mailer/smtp_server.dart';
import 'package:intl/intl.dart';
import 'package:crypton/crypton.dart';
class Mailer {
//the variable below we use to encrypt and decrypt the password
RSAKeypair _rsaKeypair = RSAKeypair.fromRandom();
//Below we set the password as a private variable
String _password = 'mySecurePassword';
//We set an encrypted variable that will store the encrypted password;
String _encrypted;
//The function below sets the encrypted variable by assigning it the encrypted value of the password
void setEncrypt () {
_encrypted = _rsaKeypair.publicKey.encrypt(_password);
}
//The function below is responsible for sending the email to the recipients and it is what we call when we want to send an email
emailSender({#required String emailRecipient, #required List<String> paths}) async {
//We call the setEncrypt() function to assign the correct value to the encrypted variable
setEncrypt();
String username = 'email#email.com';
//We asign the decrypted value of encrypted to the password we provide to the smtpServer
String password = _rsaKeypair.privateKey.decrypt(_encrypted);
//The rest of sending an email is the same.
final smtpServer = gmail(username, password);
// Use the SmtpServer class to configure an SMTP server:
// final smtpServer = SmtpServer('smtp.domain.com');
// See the named arguments of SmtpServer for further configuration
// options.
// Create our message.
Message message = Message()
..from = Address(username, 'Your name')
..recipients.add(emailRecipient)
..ccRecipients.addAll(['secondEmail#email.com'])
..subject = 'Date: ${DateFormat('dd/MM/yyyy').format(DateTime.now())}'
..text = 'This is the plain text.\nThis is line 2 of the text part.'
..html = "<h1>Hi:</h1>\n<p>This is some html</p>\n<p>Greetings, mailer.dart</p>";
for (String path in paths) {
message
..attachments.add(
FileAttachment(
File(
path,
),
),
);
}
var connection = PersistentConnection(smtpServer);
// Send the first message
await connection.send(message);
// send the equivalent message
//await connection.send(equivalentMessage);
// close the connection
await connection.close();
}
}
This was my approach to solving the issue of storing passwords as plain text for sending emails using the mailer package or any package with a similar purpose.
I've got the following code...
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = "<< MY CLIENT ID>>",
ClientSecret = "<<MY CLIENT SECRET>>"
},
new[] { "https://www.googleapis.com/auth/gmail.readonly" },
"<<EMAIL ADDRESS>>",
CancellationToken.None,
new FileDataStore("Mail2.Auth.Store")).Result;
using (var client = new ImapClient())
{
// THE CODE FAILS ON THIS NEXT LINE
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate("<<EMAIL ADDRESS>>", credential.Token.AccessToken);
}
When run, the code fails on the indicated like with AuthenticationException: The remote certificate is invalid according to the validation procedure.
I initially thought that is was 'cos the account had 2-step authentication on. So, I set up another account ensuring it just used the regular authentication settings and I got the same error.
I have found a number of posts, here and elsewhere, that deal with this exception but they seem to deal with the issue of working with the SmtpClient() and here, as you can see from the code, I'm getting the error with the ImapClient().
Can anyone suggest what it is that may be the cause of the error? Is it GMail? MailKit? .NET? All of the above?
The problem is that your system does not accept the GMail's SSL certificate.
You can override client.ServerCertificateValidationCallback.
A very simple example of a solution might look like this:
client.ServerCertificateValidationCallback = () => true;
Obviously that means that if anyone ever spoofed imap.gmail.com, your software would get caught in a MITM attack, so that's not ideal.
You'll likely want to match the certificate's thumbprint against a known thumbprint or else add the certificate to your local certificate store and assign a trust level to it.
I am building a form in C#, .NET, and MVC. On the back end the form will send its contents over email. For testing, I am using a local install of hMailServer.
Initially I set HMS to run as localhost.localdomain; the SMTP setting for "local host name" is localhost. I attempted to connect to it on port 587, like so:
SmtpClient smtp = new SmtpClient
{
Host = WebConfigurationManager.AppSettings["emailServer"],
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = true,
Credentials = networkCredential
};
I have double- and triple-checked that the credentials are the mail server user and password that I set. Here they are, in case this helps:
<add key="emailUser" value="user#localhost.localdomain"/>
<add key="emailPassword" value="~~~"/>
<add key="emailServer" value="localhost.localdomain"/>
When using localhost.localdomain, sending mail throws an exception, with the outer message: "Failure sending mail", and the inner message: "The remote name could not be resolved: 'localhost.localdomain'."
So I tried using companyname.com. Sending mail throws an exception, with the outer message: "Failure sending mail", and the inner message: "Unable to connect to the remote server."
I expect either my HMS domain config is wrong or my protocol config is wrong. The HMS documentation didn't help me, but I may not have known what to look for.
ETA
hMail server status shows zero processed messages in a week, despite all my testing.
Here is how I configured it for development:
Created host file entry like following:
local.myname.com 127.0.0.1
Once done, I opened command prompt and make sure it is updated. I tested it by following:
tracert local.myname.com
It should return 127.0.0.1 if host file entry is updated.
Next, in hmail, we need to create a new domain: local.myname.com and add an email address with password. so your email address would be something like admin#local.myname.com.
Next is, in advance you need to double check the protocols configuration and IP range vs authentication configuration as well.
In my case I configured to block external incoming and outgoing emails and skipped authentication for internal emails. So basically that;s what you can do in advance - IP range configuration. Then with the development, you just need to make sure all your emails are *#local.myname.com and it should work.
Also enable logging in hmail to get detailed error that can help solve the problem because hmail's help documentation works directly with their error codes nicely.
hMail is actually good choice for real emails. For development, I would recommend using smtp4dev though.