I finally figured out how to make the function I was looking for, however the issue I am having is I would like to have it only repeat asking for the password input, instead of both the username and password.
#include "stdafx.h"
#include <iostream> // library that contains basic input output functions
#include <string> // library for c++ strings
using namespace std;
int main()
{
//Username and Password to validate credentials
const string USERNAME = "myself";
const string PASSWORD = "stanley";
const string USERNAME2 = "otherperson";
const string PASSWORD2 = "otherpassword";
//strings in which user will enter username and password
string username, password;
int passattempts = 0;
do{
// Prompting user to input username
cout << "Enter Username : ";
cin >> username;
//Checking if username length is less than 4 characters then display an error message
if (username.length() < 4)
{
cout << "Username length must be atleast 4 characters long.";
}
else //if username length is greater than 3
{
//promprting user for password
cout << "Enter Password : ";
cin >> password;
//Checking if password length is less than 6 characters then display an error message
if (password.length() < 6)
{
cout << "Password length must be atleast 6 characters long.";
}
else //if password length is greater than 5
{
//Checking if user's entered credentials are equal to actual USERNAME and PASSWORD
if (username == USERNAME && password == PASSWORD || username == USERNAME2 && password == PASSWORD2)
{
cout << "User credentials are correct!!!" << endl;
break;
}
else
{
cout << "Invalid login details" << endl;
++passattempts;
}
}
}
} while (passattempts != 3);
system("pause");
return (0);
}
Then put the entry (and check on) the username outside the password do loop.
You can always put those inside another do loop if you want to allow the user to re-enter a username that is too short. There's no rule that says you're only allowed one loop :)
something like (pseudo code)
do
{
prompt for username
read username
} while (username invalid)
do
{
prompt for password
read password
} while (password invalid)
There's a philosophical argument to be had about whether or not you tell the user why their data is invalid. I'm not being drawn into that, security people can get a bit... intense.
Related
I am creating a password validation program and I want the password to contain the following:
* Password must be between 8 to 15 characters long...
* Password must contain at least one digit
* Password must contain at least one Uppercase
* Password must contain at least one number
* Password must contain at least one lowercase
* Password must contain at least one symbol
And if the user enters an invalid password, the program should ask the user to re-enter password. But I'm stuck on how to make the user re-enter the password if its wrong. I tried using 'goto' but its not working...
#include<ctype.h>
#include<stdbool.h>
using namespace std;
bool verify_password();
int main() {
char userName;
char password[15];
cout << "\n\t\t\t\tEnter User Name: ";
cin >> userName;
cin.clear();
cin.ignore(100, '\n');
cout << "\n\t\t\t\tEnter Password: ";
cin >> password;
bool result = verify_password();
if (result) cout<<"Verified password\n";
else {
cout<<"Invalid password\n";
cout<<result;
}
system("pause>0");
}
bool verify_password(){
int lenght = strlen(password);
if (lenght < 8 || lenght > 15) return false;
bool has_upper = false;
bool has_lower = false;
bool has_symbol = false;
bool has_digit = false;
for (int i = 0; i < lenght; i++){
if(isupper(password[i])) has_upper = true;
if(islower(password[i])) has_lower = true;
if(isdigit(password[i])) has_digit = true;
if(ispunct(password[i])) has_symbol = true;
}
if(!(has_upper && has_lower && has_digit && has_symbol)) return false;
}
I see a lot of issues with this code, but the things you should change to start:
Make your verify password function ONLY verify the password. It is currently doing more than that.
Get user input in the main() function. Once you get the password here, you can do something like:
int trys = 0;
while (trys < 3) {
cout << "Enter Password: ";
cin >> password;
if (verify_password(password)) {
cout << "valid!" << endl;
break;
}
cout << "invalid..." << endl;
++trys;
}
You can use recursion to execute the function again. Replace the following:
if(!(has_upper && has_lower && has_digit && has_symbol)){
goto checkPassword;
return false;}
With recursion, such as:
if(!(has_upper && has_lower && has_digit && has_symbol))
return verify_password();
Using goto statements is not a good practice for coding, it's much clearer to use other kind of loops like while and for.
For your problem here I would suggest to re-organize the code in smaller functions:
requestUsername() //Call it to ask user for the username
requestPassword() //Call it to ask user for password
verifyPassword() //Call it to verify the provided password
Then, you could structure your main like this:
username = requestUsername();
password = requestPassword();
while(!verifyPassword(password)) //Invalid password
{
password = requestPassword();
}
Or:
username = requestUsername();
do
{
password = requestPassword();
}while(!verifyPassword(password)) //Invalid password
Hope this helps!
My external text file, contains usernames and passwords in the form:
username1
password1
username2
password2
It isn't comparing the password inputted to the password in the file for some reason. Here's the code:
userdata.open("userdata.txt");
while(getline(userdata, temp))
{
counter++;
if(counter % 2 == 1)
{
usernames.push_back(temp);
}
}
cout<<"Please enter your username: ";
cin>>username;
for(int i = 0; i < usernames.size(); i++)
{
if(username == usernames[i])
{
usernameMatch = true;
break;
}
}
while(usernameMatch == false)
{
cout<<"\nInvalid Login! Please re-input your username: ";
cin>>username;
for(int i = 0; i < usernames.size(); i++)
{
if(username == usernames[i])
{
usernameMatch = true;
break;
}
}
}
while(getline(userdata, temp))
{
counter++;
if(counter % 2 == 0)
{
passwords.push_back(temp);
}
}
cout<<"\nPlease enter your password: ";
cin>>password;
for(int i = 0; i < passwords.size(); i++)
{
if(password == passwords[i])
{
passwordMatch = true;
break;
}
}
while(passwordMatch == false)
{
cout<<"\nInvalid Login! Please re-input your password: ";
cin>>password;
for(int i = 0; i < passwords.size(); i++)
{
if(password == passwords[i])
{
passwordMatch = true;
break;
}
}
}
cout<<"\nLogin Successful!"<<endl;
userdata.close();
The username checker works, but the password checker part doesn't and just keeps on returning the "Invalid Login! Please re-input your password:" when I'm putting in the correct password.
I'm new here so please tell me if I missed anything out. Also, I can only use the libraries included since we haven't learnt any others other than ctype.h
Unfortunately we don't have all the relevant code. Based on what you've provided, I'd assume that temp, username and password are all string and that usernames and passwords are vector<string>.
First potential problems
First check that you have explicitely initialized counter=0. If you forgot that initialization, it's a random gamble.
Then, if your username or your password could contain a space, your cin>>xxx would be out of sync, since it would consider this as two different inputs. So, if the rule is one entry per line, read with getline(cin, xxx)
Serious issue in the way you read your file
You intend to read first your while file to filter out the usernames on the odd lines, then you read again the file to filter out the passwords on the even lines. But:
Your while-loop exits with the stream userdata on error: whatever you do, you will not be able to read anything until you userdata.clear() the error
Anyway, you do never rewind your file rewind. So the getline will fail even after clearing the errors because you'd still be positioned at the end of the file. So you'd need to userdata.seekg(0); to rewind.
Finally, you never reset the counter to 0. So your odd/even check will fail if the number of lines of the file is odd (and empty line at the end is sufficient to make this happen.
A much easier approach would be to read the file in one pass without rewind:
while(getline(userdata, temp))
{
counter++;
if(counter % 2 == 1) // if odd
{
usernames.push_back(temp);
}
else // if even
{
passwords.push_back(temp);
}
}
And to finish, a security breach :-)
First you check if one of the user matches the username. Ok. Then you check if the password matches a password, any password in the file, not necessarily the password corresponding to the username:
This means that a legitimate user could impersonate any other user of the system without knowing their password !!
Worse: if any user has a weak password, it's the full system that is can be compromised !!!
The right way is to find the user, keep its index (this means that i should be defined outside of the loop) and after the password is entered, you cjeck if the password matches the password at the same index.
Now, asking for the username and telling that the usename does not match before asking the password makes the work for a hacker, since it's immediately clear what data is wrong.
The right way to do this check is to ask username AND password, and then make the verification and just tell that the login is invalid (so a potential intruder doesn't know if it's the username or the password or both that are wrong):
cout<<"Please enter your username: ";
getline(cin,username);
cout<<"\nPlease enter your password: ";
getline(cin,password);
for(int i = 0; i < usernames.size(); i++)
{
if(username == usernames[i])
{
usernameMatch = true;
passwordMatch = (password == passwords[i]);
break;
}
}
while (!usernameMatch || !passwordMatch)
...
This question already has an answer here:
The Definitive C++ Book Guide and List
(1 answer)
Closed 6 years ago.
I'm new to programming and so I bought a book to help me learn C++, in the book it asks me to do a practice assignment where I must create a program that allows me to take input of multiple usernames and passwords, match them, and also allow someone who incorrectly enters information to try entering it again. I've wrote the following program in order to do so. If anyone can also shed any light on how to make the program allow for retry of username/password entry without ending the program that would also be greatly appreciated. Thank you!
#include <iostream>
#include <string>
using namespace std;
int main()
{
string username1="Varun";
string username2="Agne";
string username3="Geetha";
string username4="Mohan"; //Usernames for accounts
string pass1="PassworD";
string pass2="PASSWORD"; //Passwords for accounts
string pass3="password";
string pass4="Password";
string Uattempt; //User input for username
string Pattempt; //User input for password
cout << "Please enter your username.\n";
cin >> Uattempt;
cout << "Please enter your password \n"; //Asks for username and password entry by user
cin >> Pattempt;
if(Uattempt!=username1 || username2 || username3 || username4)
{
cout << "Access Denied. Incorrect username or password. Please retry.\n"; //If username does not match possible entries, program will ask to retry
}
if(Pattempt !=(pass1||pass2)&&(pass3||pass4)
{
cout << "Access Denied. Incorrect username or password. Please retry.\n"; //If password does not match possible entries, program will ask to retry
}
if (Uattempt&&Pattempt==username1&&pass1||username2&&pass2||username3&&pass3||username4&&pass4)
{
cout << "Access Granted. Welcome " + <<Uattempt<< + ".\n";
}
else
{
return 0;
}
}
std::string does not define || operator.
Change the following:
if(Uattempt!=username1 || username2 || username3 || username4) ...
to:
if (Uattempt!=username1 || Uattempt!=username2 || Uattempt!=username3 || Uattempt!=username4) ...
Use
if(Uattempt != username1 && Uattempt != username2 && Uattempt != username3 && Uattempt != username4)
instead of
if(Uattempt!=username1 || username2 || username3 || username4)
Consider using a map of usernames and passwords if you plan on getting a lot of them:
std::map<string, string> userandpass{
{"user1", "pass1"},
{"user2", "pass2"}};
string Uattempt, Pattempt;
std::cout << "Please enter your username.\n";
std::cin >> Uattempt;
std::cout << "Please enter your password \n"; //Asks for username and password entry by user
std::cin >> Pattempt;
auto userIt = userandpass.find(Uattempt);
if (userIt == userandpass.end())
{
std::cout << "Access Denied.";
return;
}
string &password = userIt->second;
if (password != Pattempt)
{
std::cout << "Access Denied.";
return;
}
std::cout << "Access Granted.";
When I try to get from user a username, I make the following:
#include <iostream>
using namespace std;
void main(){
char *usrn=new char[20]; //Max username length of 20 alfanumeric characters
std::string usrn_str;
while (true){
std::cout << "Enter the username(3-20 characters): ";
cin.clear();
cin.ignore();
std::cin.getline(usrn,22);
usrn_str=usrn;
if ((usrn_str.length())<3){
cout << "Introduced username too short!" << endl;
}
else if ((usrn_str.length())>=21){
cout << "Introduced username too long!" << endl;
}
else {
cout << usrn_str.c_str() ;
}
}
}
Anyway, when introducing a larger username than the allowed one, i.e 25, it shows me the message that the introduced username is too long, but in the next loop, I can't enter again the username, because it takes as I've entered the last 5 characters in the mentioned example. Summing up, if I enter a 30 length username, it discards the first 20 and sets the last 10 ones as the username, when I want to be asking the username till I get a 3-20 length username.
How could I implement it? Any help is appreciated.
Use std::getline() to read the whole user input (user input is line based). Then do the validation checkes against the input line.
bool finished = false;
std::string name;
do
{
if (std::getline(std::cin, name))
{
// You have successfully read one line of user input.
// User input is line based so this is usually the answer to
// one question.
//
// Do your validation checks here.
// If the user entered data that checks out then set
// finished to true.
}
else
{
// There was a problem reading the line.
// You need to reset the stream to a good state
// before proceeding or exit the application.
}
}
while(!finished);
I am new to CPPUnit testing and have written test for login authentication function with various test cases. But it only accepts return value zero.
The first test case should return 1 if expected and actual are the same but it only works when I change to zero. Any advice is appreciated. Thanks.
void POSUnitTest::testAuthenticate()
{
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password"),1); // valid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password"),0); //invalid username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password1"),0); //valid username, invalid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password1"),0); // invalid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate(" ","password"),0); // Empty username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser",""),0); // Valid username, empty password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("",""),0); // Empty username and password
cout << "Test 3) testAuthenticate successful.\n\n";
}
This is my Authenticate function in class POSConsole.
int POSConsole::Authenticate(string _userID, string _password)
{
bool failedLogin=false;
int returnValue=0;
_password = Encrypt (_password); //Encrypt user enter password to compare with vector
for (int index = 0; index < cashierVector.size(); index++)
{
if ( (_userID == cashierVector[index].getUserID()) &&
(_password == cashierVector[index].getPassword()))
{
returnValue=1;
system("clear");
POSMenu();
break;
}
else
{
returnValue=0;
cout << "Invalid user login information. Please try again.\n";
failCount++;
break;
}
}
return returnValue;
if (failCount == 3)
{
cout << "You have used maximum attempts to login. Your account has been locked." << endl;
exit (0);
}
}
Edited:
I think I have found the problem. My vector size shows zero when I run CPPUnit testing. I have a function to read text file data to vector. So I called the function from CPPUnit testAuthenticate function. All test cases are passed now but other unit test functions became invisible. They are not seen by the compiler if that makes senses. I have total 10 test functions but only two is being processed. I do not get any output from other test cases at all, not even fail error.
How do I solve this, please? Appreciate your help as I'm stuck in this for days now.
void POSUnitTest::testAuthenticate()
{
console.readData();
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password"),1); // valid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password"),0); //invalid username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password1"),0); //valid username, invalid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password1"),0); // invalid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate(" ","password"),0); // Empty username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser",""),0); // Valid username, empty password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("",""),0); // Empty username and password */
cout << "Test 3) testAuthenticate successful.\n\n";
}
Here's the amended function:
int POSConsole::Authenticate(string _userID, string _password)
{
bool validUser=false;
bool failedLogin=false;
int returnValue=0;
_password = Encrypt (_password);
int vectorzie = cashierVector.size();
cout << "\nVector size" << vectorzie << endl;
for (int index = 0; index < cashierVector.size(); index++)
{
if ( (_userID == cashierVector[index].getUserID()) &&
(_password == cashierVector[index].getPassword()))
{
validUser = true;
returnValue=1;
cout << "\nOk Login Return Value: " << returnValue; //this show 1
system("clear");
POSMenu();
break;
}
}
if (validUser=false) //I have changed to this from else statement
{
failedLogin=true;
returnValue=2;
cout << "\nfail Login Return Value: " << returnValue;
cout << "\nInvalid user login information. Please try again.\n";
failCount++;
cout << "\nfail count: " << failCount << endl;
}
cout << "Final Login Return Value: " << returnValue;
if (failCount == 3)
{
cout << "You have used maximum attempts to login. Your account has been locked." << endl;
exit (0);
}
return returnValue;
}
You have a break statement for both cases of the if ... else. Therefore your loop will always end after comparing to the first element of cashierVector.
If you remove both break, then your loop will keep running even if the user was already found and returnValue will be reset to 0 again.
You need to remove the break in the else-block only. In fact your else block should only be executed if no user/password combination in cashierVector matches. So it should be placed after the loop, not in it.
The block after return returnValue will never be reached by the function, because it already has returned at that point. You need to move it before the return statement. However if you do so, then your unit test will never succeed, because after the third call to Authenticate with the wrong password (as you do in the test) the program will exit via exit(0).
On a side node: This is a use case for a map instead of a vector. If you have many users then the search will take very long. In a map this is much faster and you don't need a loop.
After your edit:
if (validUser=false). Here you assign false to validUser and then test the return, which is false. Consequently this if block will never be executed. You should change it to if(validUser==false) or better if(!valid_user). You are also missing a return statement in that block. If it is executed you don't want the following part to be executed, too.