1 package fr.in2p3.jsaga.adaptor.security;
2
3 import java.lang.reflect.Field;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Map.Entry;
9
10 import org.apache.log4j.Logger;
11 import org.freedesktop.DBus;
12 import org.freedesktop.DBus.Introspectable;
13 import org.freedesktop.DBus.Properties;
14 import org.freedesktop.Secret.Collection;
15 import org.freedesktop.Secret.Item;
16 import org.freedesktop.Secret.Pair;
17 import org.freedesktop.Secret.Service;
18 import org.freedesktop.Secret.Secret;
19 import org.freedesktop.dbus.DBusConnection;
20 import org.freedesktop.dbus.DBusInterface;
21 import org.freedesktop.dbus.exceptions.DBusException;
22 import org.freedesktop.dbus.exceptions.DBusExecutionException;
23 import org.ogf.saga.context.Context;
24 import org.ogf.saga.error.IncorrectStateException;
25 import org.ogf.saga.error.NoSuccessException;
26 import org.ogf.saga.error.TimeoutException;
27 import fr.in2p3.jsaga.adaptor.base.defaults.Default;
28 import fr.in2p3.jsaga.adaptor.base.usage.U;
29 import fr.in2p3.jsaga.adaptor.base.usage.UAnd;
30 import fr.in2p3.jsaga.adaptor.base.usage.UOptional;
31 import fr.in2p3.jsaga.adaptor.base.usage.Usage;
32 import fr.in2p3.jsaga.adaptor.security.impl.UserPassSecurityCredential;
33
34
35
36
37
38
39
40
41
42
43 public abstract class SecretServiceSecurityAdaptor implements SecurityAdaptor {
44
45 protected static final String BUS_NAME = "org.freedesktop.secrets";
46 protected static final String ITEM_INTERFACE_NAME = "org.freedesktop.Secret.Item";
47 protected static final String ROOT_OBJECT_PATH = "/org/freedesktop/secrets";
48 protected static final String COLLECTION_OBJECT_PATH = ROOT_OBJECT_PATH + "/collection";
49 protected static final String COLLECTION = "Collection";
50 protected static final String ID = "Id";
51 protected static final String LABEL = "Label";
52
53 protected abstract String getDefaultCollection();
54
55 public Class getSecurityCredentialClass() {
56 return UserPassSecurityCredential.class;
57 }
58
59 public Usage getUsage() {
60 return new UAnd.Builder()
61 .and(new U(COLLECTION))
62 .and(new UOptional(ID))
63 .and(new UOptional(LABEL))
64 .and(new U(Context.USERID))
65 .build();
66 }
67
68 public Default[] getDefaults(Map attributes) throws IncorrectStateException {
69 return new Default[]{
70 new Default(Context.USERID, System.getProperty("user.name")),
71 new Default(COLLECTION, getDefaultCollection()),
72 };
73 }
74
75
76 public SecurityCredential createSecurityCredential(int usage,
77 Map attributes, String contextId) throws IncorrectStateException, TimeoutException, NoSuccessException {
78 DBusConnection conn;
79 try {
80
81 final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
82 sysPathsField.setAccessible(true);
83 sysPathsField.set(null, null);
84
85 try {
86 conn = DBusConnection.getConnection(DBusConnection.SESSION);
87 } catch (UnsatisfiedLinkError ule) {
88 throw new NoSuccessException(ule.getMessage() + "; check that java.library.path points to the location /path/to/libmatthew/lib/jni");
89 }
90
91 String objectPath;
92 Introspectable in;
93 Properties prop;
94 DBusInterface dbusSession=null;
95 String id;
96 String label;
97 Secret secret;
98
99 objectPath = ROOT_OBJECT_PATH;
100
101 in = (Introspectable) conn.getRemoteObject(BUS_NAME, objectPath, Introspectable.class);
102 try {
103 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug(in.Introspect());
104 } catch (DBus.Error.ServiceUnknown su) {
105 throw new NoSuccessException("Your Gnome keyring or KDE KWallet should be installed and running");
106 }
107
108 Service serv = (Service) conn.getRemoteObject(BUS_NAME, objectPath, Service.class);
109
110 Pair<org.freedesktop.dbus.Variant,DBusInterface> osr = serv.OpenSession("plain", new org.freedesktop.dbus.Variant(""));
111 dbusSession = osr.b;
112
113
114 objectPath = COLLECTION_OBJECT_PATH + "/" + (String) attributes.get(COLLECTION);
115 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug("ObjectPath="+objectPath);
116 in = (Introspectable) conn.getRemoteObject(BUS_NAME, objectPath, Introspectable.class);
117 try {
118 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug(in.Introspect());
119 } catch (DBusExecutionException dbee) {
120 if (dbee.getType().equals(org.freedesktop.Secret.Error.NoSuchObject.class.getCanonicalName())) {
121 throw new NoSuccessException("The collection '" + (String) attributes.get(COLLECTION) + "' does not exist");
122 }
123 }
124
125
126 if (attributes.containsKey(ID)) {
127 id = (String) attributes.get(ID);
128 objectPath = objectPath + "/" + id;
129 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug("ObjectPath="+objectPath);
130 in = (Introspectable) conn.getRemoteObject(BUS_NAME, objectPath, Introspectable.class);
131 try {
132 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug(in.Introspect());
133 } catch (DBusExecutionException dbee) {
134 if (dbee.getType().equals(org.freedesktop.Secret.Error.NoSuchObject.class.getCanonicalName())) {
135 throw new NoSuccessException("Found no item with identifier '" + id + "'");
136 }
137 }
138
139 prop = (Properties) conn.getRemoteObject(BUS_NAME, objectPath, Properties.class);
140 Item item = (Item) conn.getRemoteObject(BUS_NAME, objectPath, Item.class);
141 try {
142 secret = item.GetSecret(dbusSession);
143 } catch (DBusExecutionException dbee) {
144 if (dbee.getType().equals(org.freedesktop.Secret.Error.IsLocked.class.getCanonicalName())) {
145
146
147
148 throw new NoSuccessException("The item is locked. Please unlock before using it.");
149 } else {
150 throw new NoSuccessException(dbee);
151 }
152 }
153 } else {
154
155 Collection collection = (Collection) conn.getRemoteObject(BUS_NAME, objectPath, Collection.class);
156
157 HashMap<String, String> searchprop = new HashMap<String, String>();
158
159 Iterator<?> it = attributes.entrySet().iterator();
160 while (it.hasNext()) {
161 Map.Entry attr = (Entry) it.next();
162 if(attr.getKey().toString().startsWith("Attribute-")) {
163 String key = attr.getKey().toString().substring("Attribute-".length());
164 searchprop.put(key, (String)attr.getValue());
165 }
166 }
167
168
169 Pair<List<DBusInterface>,List<DBusInterface>> itemList = collection.SearchItems(searchprop);
170 List<DBusInterface> unlockedItems = itemList.a;
171 List<DBusInterface> lockedItems = itemList.b;
172 if (lockedItems.size()+unlockedItems.size() == 0) {
173 throw new NoSuccessException("The collection is empty");
174 }
175 secret = null;
176
177
178 for (int i=0; i<unlockedItems.size(); i++) {
179 prop = (Properties)unlockedItems.get(i);
180
181 if (attributes.containsKey(LABEL)) {
182 label = (String) attributes.get(LABEL);
183 String foundLabel = (String) prop.Get(ITEM_INTERFACE_NAME, LABEL);
184 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug("found unlocked: " + foundLabel);
185 if (foundLabel.equals(label)) {
186
187
188
189 secret = getItem(conn,prop).GetSecret(dbusSession);
190 break;
191 }
192 } else {
193 secret = getItem(conn,prop).GetSecret(dbusSession);
194 break;
195 }
196 }
197 if (secret==null) {
198
199 for (int i=0; i<lockedItems.size(); i++) {
200 if (attributes.containsKey(LABEL)) {
201 label = (String) attributes.get(LABEL);
202 prop = (Properties)lockedItems.get(i);
203 String foundLabel = (String) prop.Get(ITEM_INTERFACE_NAME, LABEL);
204 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug("found locked: " + foundLabel);
205 if (foundLabel.equals(label)) {
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223 Logger.getLogger(SecretServiceSecurityAdaptor.class).debug(unlockedItems.size());
224 throw new NoSuccessException("The item is locked. Please unlock before using it.");
225 }
226 }
227 }
228 throw new NoSuccessException("No matching passwords");
229 }
230 }
231 byte[] pw = new byte[secret.value.size()];
232 for (int i=0; i<pw.length; i++) {
233 pw[i] = secret.value.get(i);
234 }
235 String password = new String(pw);
236 return new UserPassSecurityCredential((String) attributes.get(Context.USERID),password);
237 } catch (DBusException e) {
238 throw new NoSuccessException(e);
239 } catch (SecurityException e) {
240 throw new NoSuccessException(e);
241 } catch (NoSuchFieldException e) {
242 throw new NoSuccessException(e);
243 } catch (IllegalArgumentException e) {
244 throw new NoSuccessException(e);
245 } catch (IllegalAccessException e) {
246 throw new NoSuccessException(e);
247 }
248 }
249
250
251
252 private Item getItem(DBusConnection c , Properties p) throws DBusException {
253 return (Item) c.getRemoteObject(BUS_NAME, p.toString().split(":")[2], Item.class);
254 }
255 }