1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.dataConnector;
18
19 import java.io.Serializable;
20 import java.sql.Connection;
21 import java.sql.PreparedStatement;
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import java.sql.Timestamp;
25 import java.sql.Types;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import javax.sql.DataSource;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35
36
37
38
39
40 public class StoredIDStore {
41
42
43 private final Logger log = LoggerFactory.getLogger(StoredIDStore.class);
44
45
46 private DataSource dataSource;
47
48
49 private final String table = "shibpid";
50
51
52 private final String localEntityColumn = "localEntity";
53
54
55 private final String peerEntityColumn = "peerEntity";
56
57
58 private final String principalNameColumn = "principalName";
59
60
61 private final String localIdColumn = "localId";
62
63
64 private final String persistentIdColumn = "persistentId";
65
66
67 private final String peerProvidedIdColumn = "peerProvidedId";
68
69
70 private final String createTimeColumn = "creationDate";
71
72
73 private final String deactivationTimeColumn = "deactivationDate";
74
75
76 private final String idEntrySelectSQL = "SELECT * FROM " + table + " WHERE ";
77
78
79 private final String deactivateIdSQL = "UPDATE " + table + " SET " + deactivationTimeColumn + "= ? WHERE "
80 + persistentIdColumn + "= ?";
81
82
83
84
85
86
87 public StoredIDStore(DataSource source) {
88 dataSource = source;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 public int getNumberOfPersistentIdEntries(String localEntity, String peerEntity, String localId)
103 throws SQLException {
104 StringBuilder sqlBuilder = new StringBuilder();
105 sqlBuilder.append("SELECT");
106 sqlBuilder.append(" count(").append(persistentIdColumn).append(")");
107 sqlBuilder.append(" FROM ").append(table).append(" WHERE ");
108 sqlBuilder.append(localEntityColumn).append(" = ?");
109 sqlBuilder.append(" AND ");
110 sqlBuilder.append(peerEntityColumn).append(" = ?");
111 sqlBuilder.append(" AND ");
112 sqlBuilder.append(localIdColumn).append(" = ?");
113
114 String sql = sqlBuilder.toString();
115 Connection dbConn = dataSource.getConnection();
116 try {
117 log.debug("Selecting number of persistent ID entries based on prepared sql statement: {}", sql);
118 PreparedStatement statement = dbConn.prepareStatement(sql);
119
120 log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
121 statement.setString(1, localEntity);
122 log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
123 statement.setString(2, peerEntity);
124 log.debug("Setting prepared statement parameter {}: {}", 3, localId);
125 statement.setString(3, localId);
126
127 ResultSet rs = statement.executeQuery();
128 rs.next();
129 return rs.getInt(1);
130 } finally {
131 try {
132 if (dbConn != null && !dbConn.isClosed()) {
133 dbConn.close();
134 }
135 } catch (SQLException e) {
136 log.error("Error closing database connection", e);
137 }
138 }
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152 public List<PersistentIdEntry> getPersistentIdEntries(String localEntity, String peerEntity, String localId)
153 throws SQLException {
154 StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
155 sqlBuilder.append(localEntityColumn).append(" = ?");
156 sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
157 sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
158 String sql = sqlBuilder.toString();
159
160 log.debug("Selecting all persistent ID entries based on prepared sql statement: {}", sql);
161
162 Connection dbConn = dataSource.getConnection();
163 try {
164 PreparedStatement statement = dbConn.prepareStatement(sql);
165
166 log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
167 statement.setString(1, localEntity);
168 log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
169 statement.setString(2, peerEntity);
170 log.debug("Setting prepared statement parameter {}: {}", 3, localId);
171 statement.setString(3, localId);
172
173 return getIdentifierEntries(statement);
174 } finally {
175 try {
176 if (dbConn != null && !dbConn.isClosed()) {
177 dbConn.close();
178 }
179 } catch (SQLException e) {
180 log.error("Error closing database connection", e);
181 }
182 }
183 }
184
185
186
187
188
189
190
191
192
193
194 public PersistentIdEntry getActivePersistentIdEntry(String persistentId) throws SQLException {
195 return getPersistentIdEntry(persistentId, true);
196 }
197
198
199
200
201
202
203
204
205
206
207
208 public PersistentIdEntry getPersistentIdEntry(String persistentId, boolean onlyActiveId) throws SQLException {
209 StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
210 sqlBuilder.append(persistentIdColumn).append(" = ?");
211 if (onlyActiveId) {
212 sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NULL");
213 }
214 String sql = sqlBuilder.toString();
215
216 log.debug("Selecting persistent ID entry based on prepared sql statement: {}", sql);
217
218 Connection dbConn = dataSource.getConnection();
219 try {
220 PreparedStatement statement = dbConn.prepareStatement(sql);
221
222 log.debug("Setting prepared statement parameter {}: {}", 1, persistentId);
223 statement.setString(1, persistentId);
224
225 List<PersistentIdEntry> entries = getIdentifierEntries(statement);
226
227 if (entries == null || entries.size() == 0) {
228 return null;
229 }
230
231 if (entries.size() > 1) {
232 log.warn("More than one identifier found, only the first will be used");
233 }
234
235 return entries.get(0);
236 } finally {
237 try {
238 if (dbConn != null && !dbConn.isClosed()) {
239 dbConn.close();
240 }
241 } catch (SQLException e) {
242 log.error("Error closing database connection", e);
243 }
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258 public PersistentIdEntry getActivePersistentIdEntry(String localEntity, String peerEntity, String localId)
259 throws SQLException {
260 StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
261 sqlBuilder.append(localEntityColumn).append(" = ?");
262 sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
263 sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
264 sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NULL");
265 String sql = sqlBuilder.toString();
266
267 log.debug("Selecting active persistent ID entry based on prepared sql statement: {}", sql);
268 Connection dbConn = dataSource.getConnection();
269 try {
270 PreparedStatement statement = dbConn.prepareStatement(sql);
271
272 log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
273 statement.setString(1, localEntity);
274 log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
275 statement.setString(2, peerEntity);
276 log.debug("Setting prepared statement parameter {}: {}", 3, localId);
277 statement.setString(3, localId);
278
279 log.debug("Getting active persistent Id entries.");
280 List<PersistentIdEntry> entries = getIdentifierEntries(statement);
281
282 if (entries == null || entries.size() == 0) {
283 return null;
284 }
285
286 if (entries.size() > 1) {
287 log.warn("More than one active identifier, only the first will be used");
288 }
289
290 return entries.get(0);
291 } finally {
292 try {
293 if (dbConn != null && !dbConn.isClosed()) {
294 dbConn.close();
295 }
296 } catch (SQLException e) {
297 log.error("Error closing database connection", e);
298 }
299 }
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313 public List<PersistentIdEntry> getDeactivatedPersistentIdEntries(String localEntity, String peerEntity,
314 String localId) throws SQLException {
315 StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
316 sqlBuilder.append(localEntityColumn).append(" = ?");
317 sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
318 sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
319 sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NOT NULL");
320 String sql = sqlBuilder.toString();
321
322 log.debug("Selecting deactivated persistent ID entries based on prepared sql statement: {}", sql);
323 Connection dbConn = dataSource.getConnection();
324 try {
325 PreparedStatement statement = dbConn.prepareStatement(sql);
326
327 log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
328 statement.setString(1, localEntity);
329 log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
330 statement.setString(2, peerEntity);
331 log.debug("Setting prepared statement parameter {}: {}", 3, localId);
332 statement.setString(3, localId);
333
334 log.debug("Getting deactivated persistent Id entries");
335 List<PersistentIdEntry> entries = getIdentifierEntries(statement);
336
337 if (entries == null || entries.size() == 0) {
338 return null;
339 }
340
341 return entries;
342 } finally {
343 try {
344 if (dbConn != null && !dbConn.isClosed()) {
345 dbConn.close();
346 }
347 } catch (SQLException e) {
348 log.error("Error closing database connection", e);
349 }
350 }
351 }
352
353
354
355
356
357
358
359
360 public void storePersistentIdEntry(PersistentIdEntry entry) throws SQLException {
361
362 StringBuilder sqlBuilder = new StringBuilder("INSERT INTO ");
363 sqlBuilder.append(table).append(" (");
364 sqlBuilder.append(localEntityColumn).append(", ");
365 sqlBuilder.append(peerEntityColumn).append(", ");
366 sqlBuilder.append(principalNameColumn).append(", ");
367 sqlBuilder.append(localIdColumn).append(", ");
368 sqlBuilder.append(persistentIdColumn).append(", ");
369 sqlBuilder.append(peerProvidedIdColumn).append(", ");
370 sqlBuilder.append(createTimeColumn);
371 sqlBuilder.append(") VALUES (?, ?, ?, ?, ?, ?, ?)");
372
373 String sql = sqlBuilder.toString();
374
375 Connection dbConn = dataSource.getConnection();
376 try {
377 log.debug("Storing persistent ID entry based on prepared sql statement: {}", sql);
378 PreparedStatement statement = dbConn.prepareStatement(sql);
379
380 log.debug("Setting prepared statement parameter {}: {}", 1, entry.getLocalEntityId());
381 statement.setString(1, entry.getLocalEntityId());
382 log.debug("Setting prepared statement parameter {}: {}", 2, entry.getPeerEntityId());
383 statement.setString(2, entry.getPeerEntityId());
384 log.debug("Setting prepared statement parameter {}: {}", 3, entry.getPrincipalName());
385 statement.setString(3, entry.getPrincipalName());
386 log.debug("Setting prepared statement parameter {}: {}", 4, entry.getLocalId());
387 statement.setString(4, entry.getLocalId());
388 log.debug("Setting prepared statement parameter {}: {}", 5, entry.getPersistentId());
389 statement.setString(5, entry.getPersistentId());
390
391 if (entry.getPeerProvidedId() == null) {
392 log.debug("Setting prepared statement parameter {}: {}", 6, Types.NULL);
393 statement.setNull(6, Types.NULL);
394 } else {
395 log.debug("Setting prepared statement parameter {}: {}", 6, entry.getPeerProvidedId());
396 statement.setString(6, entry.getPeerProvidedId());
397 }
398 Timestamp timestamp = new Timestamp(System.currentTimeMillis());
399 log.debug("Setting prepared statement parameter {}: {}", 7, timestamp.toString());
400 statement.setTimestamp(7, timestamp);
401
402 statement.executeUpdate();
403 } finally {
404 try {
405 if (dbConn != null && !dbConn.isClosed()) {
406 dbConn.close();
407 }
408 } catch (SQLException e) {
409 log.error("Error closing database connection", e);
410 }
411 }
412 }
413
414
415
416
417
418
419
420
421
422 public void deactivatePersistentId(String persistentId, Timestamp deactivation) throws SQLException {
423 Timestamp deactivationTime = deactivation;
424 if (deactivationTime == null) {
425 deactivationTime = new Timestamp(System.currentTimeMillis());
426 }
427
428 Connection dbConn = dataSource.getConnection();
429 try {
430 log.debug("Deactivating persistent id {} as of {}", persistentId, deactivationTime.toString());
431 PreparedStatement statement = dbConn.prepareStatement(deactivateIdSQL);
432 statement.setTimestamp(1, deactivationTime);
433 statement.setString(2, persistentId);
434 statement.executeUpdate();
435 } finally {
436 try {
437 if (dbConn != null && !dbConn.isClosed()) {
438 dbConn.close();
439 }
440 } catch (SQLException e) {
441 log.error("Error closing database connection", e);
442 }
443 }
444 }
445
446
447
448
449
450
451
452
453
454
455 protected List<PersistentIdEntry> getIdentifierEntries(PreparedStatement statement) throws SQLException {
456 List<PersistentIdEntry> entries;
457 Connection dbConn = dataSource.getConnection();
458 try {
459 ResultSet rs = statement.executeQuery();
460 entries = buildIdentifierEntries(rs);
461 log.debug("{} persistent ID entries retrieved", entries.size());
462 return entries;
463 } finally {
464 try {
465 if (dbConn != null && !dbConn.isClosed()) {
466 dbConn.close();
467 }
468 } catch (SQLException e) {
469 log.error("Error closing database connection", e);
470 }
471 }
472 }
473
474
475
476
477
478
479
480
481
482
483 protected List<PersistentIdEntry> buildIdentifierEntries(ResultSet resultSet) throws SQLException {
484 ArrayList<PersistentIdEntry> entries = new ArrayList<PersistentIdEntry>();
485
486 PersistentIdEntry entry;
487 while (resultSet.next()) {
488 entry = new PersistentIdEntry();
489 entry.setLocalEntityId(resultSet.getString(localEntityColumn));
490 entry.setPeerEntityId(resultSet.getString(peerEntityColumn));
491 entry.setPrincipalName(resultSet.getString(principalNameColumn));
492 entry.setPersistentId(resultSet.getString(persistentIdColumn));
493 entry.setLocalId(resultSet.getString(localIdColumn));
494 entry.setPeerProvidedId(resultSet.getString(peerProvidedIdColumn));
495 entry.setCreationTime(resultSet.getTimestamp(createTimeColumn));
496 entry.setDeactivationTime(resultSet.getTimestamp(deactivationTimeColumn));
497 entries.add(entry);
498
499 log.trace("");
500 }
501
502 return entries;
503 }
504
505
506 public class PersistentIdEntry implements Serializable {
507
508
509 private static final long serialVersionUID = -8711779466442306767L;
510
511
512 private String localEntityId;
513
514
515 private String peerEntityId;
516
517
518 private String principalName;
519
520
521 private String localId;
522
523
524 private String persistentId;
525
526
527 private String peerProvidedId;
528
529
530 private Timestamp creationTime;
531
532
533 private Timestamp deactivationTime;
534
535
536 public PersistentIdEntry() {
537 }
538
539
540
541
542
543
544 public String getLocalEntityId() {
545 return localEntityId;
546 }
547
548
549
550
551
552
553 public void setLocalEntityId(String id) {
554 localEntityId = id;
555 }
556
557
558
559
560
561
562 public String getPeerEntityId() {
563 return peerEntityId;
564 }
565
566
567
568
569
570
571 public void setPeerEntityId(String id) {
572 peerEntityId = id;
573 }
574
575
576
577
578
579
580 public String getPrincipalName() {
581 return principalName;
582 }
583
584
585
586
587
588
589 public void setPrincipalName(String name) {
590 principalName = name;
591 }
592
593
594
595
596
597
598 public String getLocalId() {
599 return localId;
600 }
601
602
603
604
605
606
607 public void setLocalId(String id) {
608 localId = id;
609 }
610
611
612
613
614
615
616 public String getPersistentId() {
617 return persistentId;
618 }
619
620
621
622
623
624
625 public void setPersistentId(String id) {
626 persistentId = id;
627 }
628
629
630
631
632
633
634 public String getPeerProvidedId() {
635 return peerProvidedId;
636 }
637
638
639
640
641
642
643 public void setPeerProvidedId(String id) {
644 peerProvidedId = id;
645 }
646
647
648
649
650
651
652 public Timestamp getCreationTime() {
653 return creationTime;
654 }
655
656
657
658
659
660
661 public void setCreationTime(Timestamp time) {
662 creationTime = time;
663 }
664
665
666
667
668
669
670 public Timestamp getDeactivationTime() {
671 return deactivationTime;
672 }
673
674
675
676
677
678
679 public void setDeactivationTime(Timestamp time) {
680 this.deactivationTime = time;
681 }
682
683
684 public String toString() {
685 StringBuilder stringForm = new StringBuilder("PersistentIdEntry{");
686 stringForm.append("persistentId:").append(persistentId).append(", ");
687 stringForm.append("localEntityId:").append(localEntityId).append(", ");
688 stringForm.append("peerEntityId:").append(peerEntityId).append(", ");
689 stringForm.append("localId:").append(localId).append(", ");
690 stringForm.append("principalName:").append(principalName).append(", ");
691 stringForm.append("peerProvidedId:").append(peerProvidedId).append(", ");
692 stringForm.append("creationTime:").append(creationTime).append(", ");
693 stringForm.append("deactivationTime:").append(deactivationTime).append(", ");
694 stringForm.append("}");
695 return stringForm.toString();
696 }
697 }
698 }