Crossfire JXClient, Trunk
AclEdit.java
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of Oracle nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 import java.nio.file.*;
42 import java.nio.file.attribute.*;
43 import java.io.IOException;
44 import java.util.*;
45 import java.util.regex.Pattern;
46 
51 public class AclEdit {
52 
53  // parse string as list of ACE permissions separated by /
54  static Set<AclEntryPermission> parsePermissions(String permsString) {
55  Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>();
56  String[] result = permsString.split("/");
57  for (String s : result) {
58  if (s.equals(""))
59  continue;
60  try {
61  perms.add(AclEntryPermission.valueOf(s.toUpperCase()));
62  } catch (IllegalArgumentException x) {
63  System.err.format("Invalid permission '%s'\n", s);
64  System.exit(-1);
65  }
66  }
67  return perms;
68  }
69 
70  // parse string as list of ACE flags separated by /
71  static Set<AclEntryFlag> parseFlags(String flagsString) {
72  Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>();
73  String[] result = flagsString.split("/");
74  for (String s : result) {
75  if (s.equals(""))
76  continue;
77  try {
78  flags.add(AclEntryFlag.valueOf(s.toUpperCase()));
79  } catch (IllegalArgumentException x) {
80  System.err.format("Invalid flag '%s'\n", s);
81  System.exit(-1);
82  }
83  }
84  return flags;
85  }
86 
87  // parse ACE type
88  static AclEntryType parseType(String typeString) {
89  // FIXME: support audit and alarm types in the future
90  if (typeString.equalsIgnoreCase("allow"))
91  return AclEntryType.ALLOW;
92  if (typeString.equalsIgnoreCase("deny"))
93  return AclEntryType.DENY;
94  System.err.format("Invalid type '%s'\n", typeString);
95  System.exit(-1);
96  return null; // keep compiler happy
97  }
98 
103  static AclEntry parseAceString(String s,
104  UserPrincipalLookupService lookupService)
105  {
106  String[] result = s.split(":");
107 
108  // must have at least 3 components (username:perms:type)
109  if (result.length < 3)
110  usage();
111 
112  int index = 0;
113  int remaining = result.length;
114 
115  // optional first component can indicate user or group type
116  boolean isGroup = false;
117  if (result[index].equalsIgnoreCase("user") ||
118  result[index].equalsIgnoreCase("group"))
119  {
120  if (--remaining < 3)
121  usage();
122  isGroup = result[index++].equalsIgnoreCase("group");
123  }
124 
125  // user and permissions required
126  String userString = result[index++]; remaining--;
127  String permsString = result[index++]; remaining--;
128 
129  // flags are optional
130  String flagsString = "";
131  String typeString = null;
132  if (remaining == 1) {
133  typeString = result[index++];
134  } else {
135  if (remaining == 2) {
136  flagsString = result[index++];
137  typeString = result[index++];
138  } else {
139  usage();
140  }
141  }
142 
143  // lookup UserPrincipal
144  UserPrincipal user = null;
145  try {
146  user = (isGroup) ?
147  lookupService.lookupPrincipalByGroupName(userString) :
148  lookupService.lookupPrincipalByName(userString);
149  } catch (UserPrincipalNotFoundException x) {
150  System.err.format("Invalid %s '%s'\n",
151  ((isGroup) ? "group" : "user"),
152  userString);
153  System.exit(-1);
154  } catch (IOException x) {
155  System.err.format("Lookup of '%s' failed: %s\n", userString, x);
156  System.exit(-1);
157  }
158 
159  // map string representation of permissions, flags, and type
160  Set<AclEntryPermission> perms = parsePermissions(permsString);
161  Set<AclEntryFlag> flags = parseFlags(flagsString);
162  AclEntryType type = parseType(typeString);
163 
164  // build the ACL entry
165  return AclEntry.newBuilder()
166  .setType(type)
167  .setPrincipal(user)
168  .setPermissions(perms).setFlags(flags).build();
169  }
170 
171  static void usage() {
172  System.err.println("usage: java AclEdit [ACL-operation] file");
173  System.err.println("");
174  System.err.println("Example 1: Prepends access control entry to the begining of the myfile's ACL");
175  System.err.println(" java AclEdit A+alice:read_data/read_attributes:allow myfile");
176  System.err.println("");
177  System.err.println("Example 2: Remove the entry at index 6 of myfile's ACL");
178  System.err.println(" java AclEdit A6- myfile");
179  System.err.println("");
180  System.err.println("Example 3: Replace the entry at index 2 of myfile's ACL");
181  System.err.println(" java AclEdit A2=bob:write_data/append_data:deny myfile");
182  System.exit(-1);
183  }
184 
185  static enum Action {
186  PRINT,
187  ADD,
188  REMOVE,
189  REPLACE;
190  }
191 
195  public static void main(String[] args) throws IOException {
196  Action action = null;
197  int index = -1;
198  String entryString = null;
199 
200  // parse arguments
201  if (args.length < 1 || args[0].equals("-help") || args[0].equals("-?"))
202  usage();
203 
204  if (args.length == 1) {
205  action = Action.PRINT;
206  } else {
207  String s = args[0];
208 
209  // A[index]+entry
210  if (Pattern.matches("^A[0-9]*\\+.*", s)) {
211  String[] result = s.split("\\+", 2);
212  if (result.length == 2) {
213  if (result[0].length() < 2) {
214  index = 0;
215  } else {
216  index = Integer.parseInt(result[0].substring(1));
217  }
218  entryString = result[1];
219  action = Action.ADD;
220  }
221  }
222 
223  // Aindex-
224  if (Pattern.matches("^A[0-9]+\\-", s)) {
225  String[] result = s.split("\\-", 2);
226  if (result.length == 2) {
227  index = Integer.parseInt(result[0].substring(1));
228  entryString = result[1];
229  action = Action.REMOVE;
230  }
231  }
232 
233  // Aindex=entry
234  if (Pattern.matches("^A[0-9]+=.*", s)) {
235  String[] result = s.split("=", 2);
236  if (result.length == 2) {
237  index = Integer.parseInt(result[0].substring(1));
238  entryString = result[1];
239  action = Action.REPLACE;
240  }
241  }
242  }
243  if (action == null)
244  usage();
245 
246  int fileArg = (action == Action.PRINT) ? 0 : 1;
247  Path file = Paths.get(args[fileArg]);
248 
249  // read file's ACL
250  AclFileAttributeView view =
251  Files.getFileAttributeView(file, AclFileAttributeView.class);
252  if (view == null) {
253  System.err.println("ACLs not supported on this platform");
254  System.exit(-1);
255  }
256  List<AclEntry> acl = view.getAcl();
257 
258  switch (action) {
259  // print ACL
260  case PRINT : {
261  for (int i=0; i<acl.size(); i++) {
262  System.out.format("%5d: %s\n", i, acl.get(i));
263  }
264  break;
265  }
266 
267  // add ACE to existing ACL
268  case ADD: {
269  AclEntry entry = parseAceString(entryString, file
270  .getFileSystem().getUserPrincipalLookupService());
271  if (index >= acl.size()) {
272  acl.add(entry);
273  } else {
274  acl.add(index, entry);
275  }
276  view.setAcl(acl);
277  break;
278  }
279 
280  // remove ACE
281  case REMOVE: {
282  if (index >= acl.size()) {
283  System.err.format("Index '%d' is invalid", index);
284  System.exit(-1);
285  }
286  acl.remove(index);
287  view.setAcl(acl);
288  break;
289  }
290 
291  // replace ACE
292  case REPLACE: {
293  if (index >= acl.size()) {
294  System.err.format("Index '%d' is invalid", index);
295  System.exit(-1);
296  }
297  AclEntry entry = parseAceString(entryString, file
298  .getFileSystem().getUserPrincipalLookupService());
299  acl.set(index, entry);
300  view.setAcl(acl);
301  break;
302  }
303  }
304  }
305 }
AclEdit.main
static void main(String[] args)
Definition: AclEdit.java:195
AclEdit
Definition: AclEdit.java:51