Project 1 Addendum

FAQ and additional information on project 1

Paul Krzyzanowski

February 2, 2022

Deadline: Sunday February 20, 2022 11:59pm

FAQ and additional information on project 3

Latest update: February 2, 2022

Running the program

We need to be able to run your program without figuring out how to invoke it. Depending on the language and your build process, we expect the following.

if an executable named <em>auth</em> is built then run
	./auth AddUser user-1 password-1
else if an object file named <em>auth.java</em> is created then run
	CLASSPATH=.:$CLASSPATH java auth AddUser user-1 password-1
else if a file named <em>auth.py</em> exists then run
	python auth.py AddUser user-1 password-1
else if a file named <em>auth.go</em> exists then run
	go run AddUser auth.go user-1 password-1

Input to the program

All input to the program must be from command-line arguments. You cannot prompt the user for commands or wait for user input. This means that the command runs, generates its output, and updates any data changes to a file so it can be available to the next command.

Output

Avoid extraneous output. Do not print extra blank lines or header information.

If the output is a Success message, simply print

Success

If the output is an Error message, simply print Error: followed by a space and a description of the error.

Error: error message here

If the output is a list from DomainInfo or TypeInfo and you’re not generating an error then print each string one per line.

alice
bob
charles

Do not use any no leading spaces or tabs in your output.

Can I use a csv file and pandas to go through and manipulate the data?

Yes, you may, as long as you include and document any necessary package or if the package is available on the iLab machines.

For SetDomain, when you say “If a user does not exist, the function should return an error.”, do you mean if the user does not exist in general or in the group? Or both?

I expect the user to not be in the group - that’s why you’re doing the SetDomain. Duplicating that action should have no consequences. You should fail if the user isn’t defined at all (AddUser was never run for that user).

Can there be multiples of the same name access permission in the system? For example, if we have: "view": (premium_user, premium_content) Can we also have: "view": (alternate_user, premium_content)

Yes, any permission can be assigned to any (domain, type) and it doesn’t have to be a unique assignment.

Do we also have to be able to remove permissions, domains, users, types? Is removing to be included as one of the commands?

No, you don’t need to remove anything. That would be important if you were building this for real deployment but you don’t need it for this assignment.

For SetDomain, what should happen if the user is already in the domain?

Nothing. It’s already in the group. Just make sure you’re not adding it twice and won’t list it twice.

Should CanAccess report an error if the operation does not exist? Or we can assume AddAccess will always create the operation file before CanAccess is called?

If the operation doesn’t exist, you should report an error. CORRECTION: CanAccess should provide an answer to the question, can user A access object B? If the operation does not exist, the answer is no. You don’t need to provide an error message.

For SetDomain the program should report: Error: user exists - if the user already exists Error: username missing - if the username is an empty string What is printed in the case that the user does not exist AND the domain name is an empty string? One or both of those errors? If the former, then which error message? Also assuming the former, ideally we’d check the missing domain first rather than opening and reading a file to check if the user exists only to later recognize that the domain was an empty string the whole time. Then, the empty domain string error should take precedence over the user not existing and in the event that the user does not exist AND the domain is missing, the program would output “Error: missing domain”. Is this expected/allowed?

You can print either message. As you mention, it makes more sense to check that the domain name looks valid (i.e., is non-empty) before doing more work.

I have a question concerning how do we check for empty strings/null values. I am using python and run python auth.py then give the commands. For example, when i give the command auth AddAccess operation domain_name type_name, how would i know if domain_name was null?

Regardless of what language you’re using, first check the # of arguments. If you have at least one argument on the command line then you can look up that string and see if you have the right number of additional arguments. For example, auth Authenticate alice bob charles
should obviously produce an error since there’s a mismatch between the # of args provided and the number expected. After that, can check to see that the user, domain, or whatever you’re getting is a non-empty string. That is, it’s not equal to “”.

Can we assume that there will there be any space in the username? How about the password? If there is a space in the password, it will be in quotes?

You can assume there will be no spaces in user, domain, and type names but you can certainly be more general and permit it. For passwords, you may have spaces. Remember that the shell processes the quotes, so you don’t need to parse them. The shell will give you four arguments:

argv[0] = "auth"
args[1] = "AddUser"
argv[2] = "paul"
args[3] = "monkey brains"

If you’re not sure how command line arguments work, write a tiny program to print them out.

Is it mandatory to store data in separate files or we can just use some data structures like a dictionary (for Python) ??

You definitely don’t need to store data in separate files. That was just an example of a super-simple way of doing this in any language. You’re welcome to use any storage structure you’d like. A more elegant solution would use a single or two files.

Just to clarify, when the project specifications say: Applications that use this service can be assumed to be trusted and trustworthy: they will not try to use the interfaces incorrectly or subvert the system in any way. Does it mean that we need not account for an incorrect number of arguments provided? Otherwise, for something like AddUser, if we were given only one argument as opposed to two, how will we know that that argument is supposed to be the username or the password? Plus, no specific error messages were specified in the instructions to display in this event.

You should do the basics: check that the command is valid and the number of arguments is correct. What this statement refers to is that there is no need to isolate and protect your validation and storage structures from the programs that use them.

You should always fail gracefully. There should be no cases where your program will crash or produce unexpected results.

So should the program do and output nothing when the number of arguments is incorrect?

That doesn’t seem user-friendly. How about errors like:

Error: too few arguments - usage: AddUser name password
Error: invalid command - blahblah
Error: too many arguments

Do the input commands need to be case sensitive? For example, if a user runs the program: ./auth adduser username password, instead of ./auth AddUser username password, do we reject the command?

Up to you. We’ll test it with the cases specified but you’re welcome to be flexible.

If there is a user named Bob, and their password is “Alice”, and then we try to add a new user Alice: “AddUser Alice password”, then if our program searches the file containing our users and passwords, it would incorrectly give an error saying “error: user exists”. Can we assume a situation like this would not happen?

You should not be searching through passwords if you’re looking for a user name. Those are distinct fields regardless of the storage structure you choose.

And for a related note, what if we try to add a user “Bo” when a user “Bob” already exists in the system?

“Bo” and “Bob” are two different strings. You should be able to handle them as distinct users.

I was wondering what would be considered correct behavior as a print out for project 1 If I do: auth SetType file my_type auth SetType file my_type auth TypeInfo my_type

Should the correct output be: [‘file’, ‘file’]

or should something like the second command be reported as an error?

Also is there a specific format we should follow when printing out every object assigned to a type? The same issue can arise with SetDomain and DomainInfo so I was wondering if that should follow the same format for those as well.

If you invoke

auth SetType file my_type

several times in a row, no harm done. my_type is essentially an attribute of the file. Think of it like setting read access for a file that already has read access set.

When you list files containing a certain attribute via TypeInfo (or when you list users), you should list unique objects and unique users. That is, if you set a file to my_type 50 times, TypeInfo will show only one occurrence.

As for output format, the preferred output format is one file name per line with no other junk. That fits into the Unix tools philosophy, which makes the output suitable for input in a pipeline of commands. auth TypeInfo my_type |grep temp Will show all the files that of type my_type that contain the word temp in it. If all the files are on one line and separated by commas, the output becomes a pain to process with linux tools.

file_1
file_2
file_3

Is it safe to trim trailing spaces off of the inputs? Also, passwords could have trailing spaces, right? What would be a safe practice for this project? Thanks

You shouldn’t be concerned with leading and trailing spaces in arguments. The shell parses out whitespace. If a user intends to insert a space and quotes the string, just use that string. For example

auth AddUser "ravi " letmein

Means that the user name is the string "ravi " - with a space at the end. It’s just whatever string is argv[2]. You won’t see the quotes, of course; the shell parses that out.

Will we be receiving any test cases?

Probably not. You should be able to write some and document them. For example:

for i in `seq 50`;do ./auth AddUser user-$i password-$i;done
for i in `seq 50`;do ./auth Authenticate user-$i password-$i;done
for i in `seq 50`;do ./auth Authenticate user-$i bad-password-$i;done

Are we required to submit documentation on our test cases? The recitation slides indicated that it’s not part of the grading.

The test cases are for yourself to validate that what you have works. Your documentation should be brief but provide a clear example of how to build and run your program. Documenting a few test cases and sample uses will allow us to take a closer look if things don’t work on our end. Without examples, we will just assume that your program does not work.

Your goal in this program is to make my life easy. If I’m confused and it takes me more than a few seconds to figure out what you submitted, how to build it, and how to run it, you will lose points.

So what did the instructions mean check for empty string? I thought it would have been like ./auth AddUser “ “ password or something like that. Or just “”.

An empty string would be something like:

auth AddUser "" password

An empty string is not a valid username. A space is not an empty string. I won’t check whether you allow a space to be a valid username so you can decide whether to allow usernames that contain whitespace.

How do we know which argument doesn’t exist? For example, AddAccess takes in an operation, domain name, type name, where the domain and type name cannot be empty strings. If the command is “AddAccess(commandA)”, how do we know if “commandA” is the operation, domain name, or type name? Do we assume it’s the operation since it’s the 1st argument?

If the user supplied the wrong # or too many arguments you won’t know what’s missing given the positional syntax. To fix that, we’d need to use flags, like:

auth AddUser -u name -p password

but this implementation is lax so all you can do is check to see if there command has the number of arguments you expect and they’re not empty strings.

Are empty parameters denoted by quotation marks “” ? Or will they be blank? For example, if the password in AddUser is missing, would it be: AddUser(“username”, “”) or AddUser(“username”)?

Write yourself a little program that loops through command-line arguments and prints them out so you can see that the shell strips out quotes from a quoted string. Just take each argument as you get it. There’s no parsing needed - just compare it to an empty string in case the user passes in a “” (or '').

Can we assume our program will live in an empty directory at first? And if a “users” file does not exist in the same directory than is it safe to assume there are no users?

I don’t know what storage structures you are using for storing your data. If you’re using subdirectories or files, you can assume they will be in the current directory (don’t use hard-coded full pathnames, like /home/user/etc/auth) but you cannot assume that the subdirectories or files have been created or exist. Your program can easily create them (e.g., the mkdir() system call).

I used Python3 for my program. Can I mention that in my documentation so the command would be: python3 auth.py AddUser user-1 password-1

It’s a bummer that python 2 & 3 are so different.  Please document the version you’re using. 

It would also help if you put something like this in your code:

import sys

if sys.version_info[0] < 3:
    raise Exception("python 3 is required for this program")

Can we use Json file to store data? or does it have to be .txt file only. Also will there be an issue if we write some of our code using list comprehension?

You can store your data in a json file if you provide the reading/writing libraries (or use ones available on iLab systems).

I don’t see a problem with using list comprehensions if you feel that will make your code easier to write. As long as it works, feel free to implement data management any way you’d like.

Should CanAccess report an error if the operation does not exist? Or we can assume AddAccess will always create the operation file before CanAccess is called? => Instructor Answer: If the operation doesn’t exist, you should report an error.

That answer was a mistake on my part. You should stick to the assignment instructions.

CanAccess should provide an answer to the question, can user A access object B? If the operation does not exist, the answer is no. You don’t need to provide an error message.

Is there any limit on how many files we can use max to store data ?? Because I am up to using six separate files??

No. You can use however many files you need. To keep things neat, you might want to put them all in some subdirectory (e.g., auth_data).

Is it guaranteed that our program will be run independently of other students? For instance, my program creates a file named “Users” in the current directory the program is run in. However, if there is already a Users file, it will just read from it.

You can assume that your files will be loaded into an empty directory. Then we will run your build process (e.g., make, shell script, copy & paste instructions). After that, your program should be ready to run.

It should not use absolute pathnames and if it needs any directories or files, the program is responsible for creating them.

Do we submit files individually or as a zip file?

The Readme and source files should be sufficient.

Canvas’s submission downloads are uglier than sakai. Sakai would create a directory structure and produce a zip file containing that structure. Canvas provides a flat list with each file name prefixed by the students name a bunch of numbers (not an ID). 

The cleanest submission would be a zip file that contains the README file and any files necessary to build the program. Do not submit any files needed to store the data. Those should be created by your program as needed.

Does our program need to output exact outputs as specified. For example, if the username or password is an empty string, could we print out an error message like “The username can’t be empty string” or “The password can’t be empty string”, or should it be exactly “Error: Username Missing” and “Error: Password Missing”.

Please follow the instructions. You can change the message but have it start with an "Error: " string or a “Success” so the response can be parsed.

For example “./auth SetDomain “” admin”, admin doesn’t exist yet. Do we only need to print the error about the user or do we need to print the error and create the admin domain? Does this also pertain to AddAccess?

Check for errors first. If the user is invalid or doesn’t exist, that’s an error. There’s no need to create the domain admin but there’s no harm done if you do so as there are no users in the domain.

will any of the inputs contains new line character(‘\n’), tab character(‘\t’), and space inside?

You may assume that names, domains, types, and operations will not contain whitespace if that makes your implementation easier.

In AddAccess if an access for an operation for a particular domain for a particular type already exists in the matrix, but the same command is input again, do we print an error saying that the access already exists, or do nothing?

There’s no need to print any warning. Do you expect Linux to complain that a file already has read access when you try to set read access?

Do we need to paste all the test cases that we used to test the program in the README because the point 3 under “Documentation and components” says to provide example error cases and success cases?

You can make the README as good or as crummy as you want. That’s up to you. At the very least, I’d expect a README file to contain examples of how you built and run your software. I’d expect it to be as in the project write-up. However, if your program doesn’t run, you’ll get a grade of 0. If your README file contains examples that show a slightly different usage than we expect, we can replicate that and give you partial credit.

The quality of your presentation is important - both in academia and in industry. In my eyes, a beautifully coded assignment (with comments where helpful) coupled with a beautiful writeup deserves a better grade than a bunch of code and cryptic documentation.

I reserve the right to deduct points for sloppy work - whether it’s code or documentation. Submit your best work.

Last modified February 2, 2022.
recycled pixels