I have a Linux server and I'm running an image resize job in Java for multiple websites on my server. The website files are owned by different OS users/groups. Newly created thumbnails/previews are owned by the user running the resize job. Now I was googleing around how to change the file owner of newly created previews/thumbnails in my resize program and came across this:
java.nio.file.Files.setOwner(Path path, UserPrincipal owner);
This would really solve my problem if it was Windows, but since a Linux file has a user and a group as owner I'm a bit in trouble. Unfortunately given method seems to only change the user ownership of the file. The group ownership remains with the group of the user running my Java resize job.
The websites are owned by different groups, so adding my resize job user to one group is no option. I also want to avoid system calls with ProcessBuilder and execute a chown on my files.
I do need to point out that the created files (preview/thumbnail) can be accessed via the website and it is not mission critical to change the group ownership, but I wanted it to be as clean as possible.
Any suggestions how I can change the group ownership of a file in Linux only using Java?
Thanks Jim Garrison for pointing me in the correct direction. Here the code, which finally solved the problem for me.
Retrieve the group owner of a file
File originalFile = new File("original.jpg"); // just as an example
GroupPrincipal group = Files.readAttributes(originalFile.toPath(), PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS).group();
Set the group owner of a file
File targetFile = new File("target.jpg");
Files.getFileAttributeView(targetFile.toPath(), PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS).setGroup(group);
I missed a complete solution, here it comes (combination of other answers and comments):
Path p = Paths.get("your file's Path");
String group = "GROUP_NAME";
UserPrincipalLookupService lookupService = FileSystems.getDefault()
.getUserPrincipalLookupService();
GroupPrincipal group = lookupService.lookupPrincipalByGroupName(group);
Files.getFileAttributeView(p, PosixFileAttributeView.class,
LinkOption.NOFOLLOW_LINKS).setGroup(group);
Be aware that only the owner of a file can change its group and only to a group he is a member of...
Take a look at the package java.nio.file.attributes and classPosixFilePermissions. This is where you can manipulate group permissions.
The purpose of this response is to elevate one of the comments received in response to the original posting to a full response level, so that it is more prominently displayed.
Here is what worked for us:
// newUser and newGroup are strings.
UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService();
UserPrincipal userPrincipal = lookupService.lookupPrincipalByName(newUser);
GroupPrincipal groupPrincipal = lookupService.lookupPrincipalByGroupName(newgroup);
Files.setAttribute(filePath, "posix:owner", userPrincipal, LinkOption.NOFOLLOW_LINKS);
Files.setAttribute(filePath, "posix:group", groupPrincipal, LinkOption.NOFOLLOW_LINKS);
Additionally we had to run the Java program as a superuser.
Related
So I'm lookign into ways to edit some of less visible setting s on a google group, in specific the one found in:
Access Settings > Settings > Moderation > Spam Messages
This setting is what I believe is spamModerationLevel in the Group settings api.
I've tested changing other settings with the same code sucesfully, but that particular attribute does not change.
This works:
DirectoryUtils client = new DirectoryUtils(); //class with my google api methods
Directory directory = client.getDirectory(); //directory instance
Group group = client.retrieveGroup(directory, "api-test"); //api-test being the group I'm testing with
group.set("name", "Testing name change");
Group modified = directory.groups().update(group.getEmail(), group).execute();
With that my group name changes with no problems. For testing the set() method I didnt use the api's setName() which does the same but now I know set() works. Now if i try this:
group.set("spamModerationLevel", "ALLOW");
Group modified = directory.groups().update(group.getEmail(), group).execute();
The group stays the same with no change to the settings I was looking to change.
I've noticed during debugging, the "group" variable has an added spamModerationLevel attribute after the set() command but when execute() returns teh group as "modified", it looks the same as "group" before the change.
Is there a way to do this change through the API that I'm missing?
Thanks,
Stephen
I'd like to create a launcher for a Java game I'm developing that will require the user to log in before the game itself can be downloaded. My idea was to have the launcher send the credentials to my webserver, and the webserver would output the location of a temporary file given the credentials were correct. However, this would be a bit tricky/inefficient, given:
The server would need to copy the game file every time someone updates, and
The webserver wouldn't know when the file was finished downloading.
Perhaps the launcher could send a request to a separate script to delete a file of the given temporary name? The problem with that is that the launcher could easily be decompiled and modified to not send the request, defeating the purpose of creating a new file.
Any suggestions as to this idea and its issues?
I would use a database, like this:
urlgenerator.php
<?php
// generate code
$code = uniqid();
// save code to database
db_save($code);
// write link
echo 'Download';
download.php
<?php
// get code from url
$single_use_code = $_GET['code'];
// check if the code is in the db
if(db_get_code($single_use_code)) {
// remove code from database as it is single use only
db_remove($single_use_code);
// start download
start_download();
} else {
// the code is not valid
die('BAD code');
}
Try something like this:
// Define a random key
$key = 'kgjiowtjiohgjiut09ig90im09yig90mi903i490ti209tgwgt';
$secondsValid = 300;
if($_GET['action'] == 'download')
{
$time = $_GET['time'];
if(time() - $time > $secondsValid)
die('Code has expired, please try again');
if($_GET['validation'] != md5($time.$key))
die('Invalid validation code');
DownloadFile();
die;
}
elseif(CredentialsAreCorrect())
{
$time = time();
header('Location: '.$_SERVER['REQUEST_URI'].'?action=download&time='.$time.'&validation='.md5($time.$key));
die;
}
else
die('Invalid credentials');
This is an easy way to give a validated user a timebombed URL (valid for 5 minutes in this case) without any nasty copying/symlinking/whatever involved, no databases, just using basic facilities that cannot be hacked as long as the key is secure. Just make sure your key has enough entropy (40+ random keypresses should do it) so no rainbow table or brute force attack is feasible.
Simple workaround: on a unix system, you can remove a file while it's in use without affecting currently-open file handles on that file. so
user requests download
script makes a symlink in the documentroot somewhere that points at wherever the file is really stored (somewhere outside of the document root)
URL to the symlink is send out as a parameter to the user.
User clicks on the donwload link, e.g. http://example.com?get=path/of/symlink
The download script fopen()'s the symlink and starts dishing out the file's contents
script REMOVES the symlink after it's been fopen()'d
Now the symlink is gone and can't be reused anymore, but the download script will still be sending data to the user because it opened the symlink/file before it was removed.
Is there any method to create a file in java that cannot be deleted.
I have googled it and found processes involving the cmd.
However, I require a pure "java" way that can be done on any platform.
Thanks in advance.
Thank you for your help.
I finally got it right.
I used the following code to deny access to user
public static void main() throws IOException
{
Path file = Paths.get("c:/b.txt");
AclFileAttributeView aclAttr = Files.getFileAttributeView(file, AclFileAttributeView.class);
//System.out.println();
UserPrincipalLookupService upls = file.getFileSystem().getUserPrincipalLookupService();
UserPrincipal user = upls.lookupPrincipalByName(System.getProperty("user.name"));
AclEntry.Builder builder = AclEntry.newBuilder();
builder.setPermissions(EnumSet.of(AclEntryPermission.APPEND_DATA, AclEntryPermission.DELETE, AclEntryPermission.DELETE_CHILD, AclEntryPermission.EXECUTE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_DATA, AclEntryPermission.READ_NAMED_ATTRS, AclEntryPermission.SYNCHRONIZE, AclEntryPermission.WRITE_ACL, AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.WRITE_NAMED_ATTRS, AclEntryPermission.WRITE_OWNER));
builder.setPrincipal(user);
builder.setType(AclEntryType.DENY);
aclAttr.setAcl(Collections.singletonList(builder.build()));
}
Try the method setPosixFilePermissions() and set the permissions to read only for all the classes of users. Refer this - http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#setPosixFilePermissions%28java.nio.file.Path,%20java.util.Set%29
If you want to create a file that can't be accidentally overwritten, then look at the various answers to this: How do i programmatically change file permissions?
If you want to create a file that the current program cannot delete at all (but a privileged one could), it might be possible by setting permissions appropriately on the parent directory, or possibly using SELinux Mandatory Access Control cleverness.
If you want to create a truly undeleteable file, then you are out of luck. I am not aware of any operating system that supports creation of files that can never be deleted. It would be an "anti-feature".
I would also agree with #Teifi's comment. Create a file that cannot ever be deleted on the user's machine is not acceptable ... unless done by, or with the authorization of the system's administrators. I would call any software that did that "malicious" too.
I am writing an attendance program in Java for use in class; my goal is to be able to have the students download the class file to their accounts (we'll be working on the same network) and then run them with their usernames and a password that will change daily. My program works fine, but I've run into a bug that I can't seem to overcome.
When it's run for the first time in any given day, attend.java will create a new text file in a specified directory on my account and then append the username of whoever ran the program to the file (currently it just appends the first argument of the program to the file, but I hope to modify it so it is more accurate and no one can give a false username), thereby compiling a list of students.
For example, running:
>> java attend desadams cheesecake
will take the given password "cheesecake" and if it matches the day's password either create a new textfile called "(today's date).txt" and write the username "desadams" to it (if it is being run for the first time that day) or else simply append the username "desadams" to the preexisting "(today's date).txt" file.
I wrote my own createFile() method that utilizes the java.nio.file package to create a file with custom permissions:
public static void createFile(File file) throws IOException{
Path newFile = file.toPath();
//create new file and set permissions
/* For the purposes of this program, the new file (the attendance list) must readable and writable to everbody
* in order for this program to work properly when run from their user, because this program both reads and modif\
ies.
*/
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxrw-rw-");
Files.createFile(newFile);
Files.setPosixFilePermissions(newFile, perms);
//set owner
UserPrincipal owner = newFile.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("desadams");
Files.setOwner(newFile, owner);
//set group
GroupPrincipal group = newFile.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByGroupName("studen\
ts");
Files.getFileAttributeView(newFile, PosixFileAttributeView.class).setGroup(group);
}
I could not create the file and set the permissions at the same time, because the umask of the account would get in the way, so I did it in two steps and it works fine.
Now we get to my problem: I can compile and run this program just fine from my own account, but in anticipation of running it from other accounts, I changed the setOwner() method to use an arbitrary username instead of my own to better simulate the conditions of running the program from a different account. And it failed. Attempting to set the owner to anyone other than the person running the program results in an "operation not permitted" error.
I already knew that the UNIX command chown would not work because none of the network accounts have access to the root account, but I didn't expect it to prevent Java from doing the same thing, though I suppose it does make sense.
Is there anyway at all to get around this? The simplest way, of course, would be to run the program myself prior to anyone else each day, so that the attendance file is created in my own username and then I wouldn't have to worry about making sure to set the owner to my username within the program itself; it will always find the attendance file and thus not have to create it with the proper file attributes. However, though that may be exactly what I do, I would like to know if anyone has a solution that suggests how to set the owner within the program itself.
Thanks, and sorry this was a long post.
If the users are sudoers on your system, you could have them do sudo java attend desadams cheesecake. However, I expect they are not sudoers, and therefore your solution where you create the file first is probably the best one.
If I call describeSnapshots() of AmazonEC2 Java interface I get a big number of snapshots as described in the documentation, because it includes all visible snapshots.
However to get the list of my snapshots, should be easy with the API, but it isn't obvious to me. I tried to pass a DescribeSnapshotsRequests object to describeSnapshots()
DescribeSnapshotsRequest req = new DescribeSnapShotRequests();
List<String> ownerId = new ArrayList<String>();
ownerId.add("....");
req.setOwnerIds(ownerId);
DescribeSnapshotsResult res = ec2.describeSnapshots(req);
However to get my user id, I printed the user id of all snapshots and manually identified mine, copied that user id, and used in the source code.
I hope there is a better way to list my snapshots, anyone knows?
Try this
req.setOwnerIds(Arrays.<String>asList("self"));
Something like this works for me to describe images.
https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html
If you specify one or more snapshot owners using the OwnerIds option,
only snapshots from the specified owners and for which you have access
are returned. The results can include the AWS account IDs of the
specified owners, amazon for snapshots owned by Amazon, or self for
snapshots that you own.
ec2.describeSnapshots(new DescribeSnapshotsRequest().withOwnerIds("self"));