My webservice using apache shiro always return unauthorized - web-services

I have this shiro.ini:
[main]
ds = org.apache.shiro.jndi.JndiObjectFactory
ds.requiredType = javax.sql.DataSource
ds.resourceName = java:/comp/env/jdbc/myDS
# JDBC realm config
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = "SELECT password FROM user WHERE username = ?"
jdbcRealm.dataSource = $ds
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
# base64 encoding, not hex in this example:
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024
jdbcRealm.credentialsMatcher = $credentialsMatcher
[urls]
/logout = logout
/** = authcBasic
Im debbuging JndiRealm in doGetAuthenticationInfo. I get an exception when shiro try to execute my authenticationQuery in getPasswordForUser method. Those are the lines that execute the select:
ps = conn.prepareStatement(authenticationQuery);
ps.setString(1, username);
My atuthenticationQuery is "SELECT password FROM user WHERE username = ?" so trying to access position 1 is invalid since it starts from position 0. Is that a bug on JndiRealm from apache shiro or i wrote my sql wrong?

Looks like you have a simple mock implementation of a realm.
For logging in to work, you needs 2 steps:
authentication (is the username/password correct)
authorization (what is the user allowed to do)
Looks like you have only created the first step, but you are just giving back the password in the return statement.
Shiro will hash the password that was entered by the user. You should have the same hash stored somewhere in your database. In the doGetAuthenticationInfo you should do a lookup based on the username that was entered and retrieve the hash (either from the db, or disk or whatever you prefer), that is what you should put in the SimpleAuthenticationInfo object and return, shiro will do the user password hashing and comparison for you.
For the second step, override the method doGetAuthorizationInfo. You could let it return an instance of SimpleAuthorixationInfo containg a set of permissions, the simplest being "*", when it has access to everything.
Creating such a method can be as simple as:
#Override
public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//here you can create custom permissions based on the principal
//that has been authenticated using your own logic
info.addStringPermission("*");
return info;
}

Related

Can I decrypt password using the private key generated in Django backend in Flutter?

I am making a password manager app where I am using asymmetric encryption to store passwords. I have created a Django backend for the app where I have stored the user's public key in the User model. During registration, I am storing the public key in the database and sending the user their private key to the Flutter app.
I am using the following function to encrypt the password and store it in the password store model:
def encrypt(data, key):
key = serialization.load_pem_public_key(
key.encode(),
backend=default_backend()
)
data = key.encrypt(
data.encode(),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return data
Now, I want to know if I can decrypt passwords or any other string data in Flutter using the private key that is generated in the Django backend. If yes, how can I do it?
Also, I don't want to pass the decrypted password from the backend to the Flutter app. I want the client-side to handle it. For this, I am storing the private key in the user's device using shared preferences in Flutter:
SharedPreferences.getInstance().then((prefs) {
prefs.setString("privateKey", widget.privateKey);
});
Can anyone help me with this?
I tried using the decryptByPrivateKey function below to decrypt a password on the client side in my Flutter app using a private key generated on my Django backend:
dynamic decryptByPrivateKey(String content) async {
final prefs = await SharedPreferences.getInstance();
final private = prefs.getString('privateKey')!;
RSAKeyParser parser = RSAKeyParser();
RSAPrivateKey privateKey = parser.parse(private) as RSAPrivateKey;
AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine());
cipher..init(false, PrivateKeyParameter<RSAPrivateKey>(privateKey));
return utf8.decode(cipher.process(Encrypted.fromBase64(content).bytes));
}
However, I got the following error related to the content parameter, and I'm not sure how to resolve it:
FormatException: Invalid character (at character 2) b'\rV\x86ldn\x171*^c\xabsAc;\xead\xea\x05C\x996o\x0e#\xe2\xed\x1c\xa21\x80d... ^
Also, I am generating and sending the private key to the client as shown in the code snippet below:
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
public_key = private_key.public_key()
public_key = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
private_key = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
private_key = private_key.decode('utf-8')
public_key = public_key.decode('utf-8')
I am hoping to be able to decrypt the password on the client side using the private key without passing the decrypted password from the backend. Can anyone help me with this issue?"

How to disable a user's password in AWS using boto3

I am auditing user passwords in AWS using boto3 and I'm not finding a way to accomplish the following CIS Benchmark: "Ensure credentials (with password enabled) unused for 90 days or greater are disabled."
I have the code to pull the password age and to pull the last time the password was used, but I do not find anything to make inactive a password.
For access keys (but not passwords), we have the following:
client = session.client('iam')
... (get user and keyid) ...
last_used = client.get_access_key_last_used(AccessKeyId=keyid)
... (determine the age of the key) ...
if age >= 90:
client.update_access_key(AccessKeyId=keyid, Status='Inactive', UserName=user)
Does anyone have any pointers?
delete_login_profile is the one you should use if you want to delete the password for the specified IAM user, which terminates the user's ability to access AWS services through the AWS Management Console.
However to prevent all user access (including CLI and API access) you must also either make any access keys inactive or delete them.
From Boto3 Documentation:
Warning
Deleting a user's password does not prevent a user from accessing AWS
through the command line interface or the API. To prevent all user
access you must also either make any access keys inactive or delete
them. For more information about making keys inactive or deleting
them, see UpdateAccessKey and DeleteAccessKey.
If you want to change the password, you should use update_login_profile boto3 API. If you want to disable the password, you need to use delete_login_profile.
boto3 documentation for update_login_profile can be found here.
boto3 documentation for delete_login_profile can be found here.
Thanks to the responders, delete_login_profile followed by a password reset using create_login_profile is exactly what I needed. I saw it in the docs, but "delete" just sounded too scary.
def getPassword(client, user):
''' get the password data from aws '''
try:
response = client.get_login_profile(UserName=user)
return response
except client.exceptions.NoSuchEntityException as e:
print(e)
return ''
# setup the client handler
client = session.client('iam')
# set the user
user = 'some.user'
# if the user has a password, execute this code block
if getPassword(client=client, user=user):
... code to test the password age here ...
... if it's too old, then ...
# remove the login_profile/password/ability to use the Console
client.delete_login_profile(UserName=user)
# set the new password
passwd = raw_input('Enter New Password: ')
# create the new login_profile with the new password and force the user to change the password on the next login
client.create_login_profile(UserName=user, Password=passwd, PasswordResetRequired=True)

Sitecore Virtual User Login Experience Profile

I need to validate user credentials from external service, therefore I'm using the VirtualUser authentication.
BuildVirtualUser, checking for the roles to set to him, saving the user Profile and then login with that name.
I'm facing a problem, that everyday that i login, with the same credentials Sitecore creates a new user in Experience Profile.
What i need to change in my code to assure that, with virtual user login, Sitecore gets the old experience profile of the user?
I was thinking in creating the user in sitecore with same generic password. Instead of using the virtual user, and authenticate directly with sitecore. Is that correct?
Here's my code:
Sitecore.Security.Accounts.User user = Sitecore.Security.Authentication.AuthenticationManager.BuildVirtualUser(sitecoreUser, true);
string roleName = #"newRole\User";
Sitecore.Security.Accounts.Role demoRole = Sitecore.Security.Accounts.Role.FromName(roleName);
if (Sitecore.Security.Accounts.Role.Exists(roleName) && !demoRole.IsMember(user, true, false))
{
user.Roles.Add(Sitecore.Security.Accounts.Role.FromName(roleName));
}
user.Profile.Name = name;
user.Profile.Email = email;
user.Profile.FullName = fullname;
user.Profile.Save();
Sitecore.Security.Authentication.AuthenticationManager.Login(user.Name);
Tracker.Initialize();
Code looks fine, but you miss one important thing: to identify your user/contact.
You need to add next line of code:
Tracker.Current.Session.Identify(email);
Please check next link to find more information about how to identify contacts:
https://doc.sitecore.net/sitecore_experience_platform/setting_up__maintaining/xdb/contacts/identifying_contacts

ASP.NET MVC4 Remember login password using cookies - Secure way?

I would like the feature for the sign in box to have the username and password automatically filled in if the user has previously been on the site and logged in successfully before. I see this implemented on many sites so I figured theres a way to do this without creating a security risk.
EDIT: According to a post this is a browser feature and should not be implemented in code because its never safe to store password anywhere.
Edited the code to reflect a new direction where Im only storing the username. However, Im not sure what to look for to see if its working. I tried to login then logout, then go to login screen again but username box still blank when the view loads in. Not sure if its the code or Im testing it the wrong way.
Login POST:
[HttpPost]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return Json(new { ok = true, message = "Login successful." });
}
}
return Json(new { ok = false, message = "The username or password you entered is invalid. Please try again." });
}
Login GET:
[HttpGet]
public ActionResult Login(string path)
{
LoginModel model = new LoginModel();
HttpCookie authCookie = System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName.ToString()];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null & !authTicket.Expired)
{
model.UserName = authTicket.UserData;
}
}
return PartialView(path, model);
}
There are couple of issues with your code. The first one is that you are adding the cookie to the Request object instead of adding it to the Response => Response.Cookies.Add(authCookie);.
The second issue is that you are creating a non-persistent cookie meaning that it will only live through the browser session. Once the user closes the browser it will be gone forever because it was never stored on the client computer. In order to create a persistent cookie you need to specify an expiration date for it which will obviously correspond for how long this cookie will be persisted on the client computer. For example if you wanted to remember for 5 days:
HttpCookie authCookie = new HttpCookie("authCookie", "cookieValue")
{
Expires = DateTime.Now.AddDays(5)
};
Another issue is that you are storing only the MD5 hash of the password inside the cookie and you expect to be able to decrypt it later with FormsAuthentication.Decrypt which is not possible. This method can decrypt values that were encrypted with the Encrypt method.
And the biggest problem of them all is the security: you should never be storing any password related stuff anywhere. The username should suffice. Browsers offer the possibility to remember passwords for given site. I would recommend you using this functionality instead of doing what you are doing.
Another possibility is to emit a persistent authentication cookie when the user logs in, so that even if he closes the browser he will be remembered as authenticated for the validity period you specified in this authentication cookie.
you don't need the actual password for the user to make sure he logged in previously. You shouldn't even save the actual password in the database. You usually only save a salted hash of that password. When the user logs in, you create a hash for that password and compare it with the hash stored in the database. If they match, he entered the correct password.
As for storing login information in a cookie, i'd then store a salted hash of that password hash in the cookie. Upon GET, you just create a salted hash of the stored password hash and compare it with the one from the cookie. If they match, the login cookie is valid. That way you never actually store any user password anywhere.
To make this more secure, the login page should be secured by SSL, otherwise the password would at least once be transmitted unencrypted.
If you're using SQL, you can generate a random number when the user first logs on. Store this number in the Users table, and also as a cookie on the user's machine. The user can then authenticate by comparing the random number with that stored on the server.
It's a good idea to timestamp the login though, so it expires after a set period of time.

Where to get the credentials to use for Authentication.asmx?

For one of our FBA enabled SharePoint site, we need to access various web services. I know that we need to invoke Authentication.asmx before we make any other SP web service call.
How do I get the currently logged in user's username & password to pass to the Authentication.asmx service?
Thanks.
Update: I tried Marek's solution with a known username and password and got a 401 for Authentication.asmx. So probably some settings are off. The admin is looking into it.
MembershipUser user = Membership.GetUser();
string username = user.UserName;
string password = user.GetPassword();
Authentication auth = new Authentication();
auth.CookieContainer = new CookieContainer();
LoginResult result = auth.Login(username, password);
if (result.ErrorCode == LoginErrorCode.NoError)
{
CookieCollection cookies = auth.CookieContainer.GetCookies(new Uri(auth.Url));
Cookie authCookie = cookies[result.CookieName];
Lists lists = new Lists();
lists.CookieContainer = new CookieContainer();
lists.CookieContainer.Add(authCookie);
lists.GetListCollection();
}
However, depending on the settings of the membership provider (is password stored in plain text, encrypted or hashed? is it required to pass the security answer to get the password?) retrieving the password may be more difficult or even impossible and you will need to ask the user for it.