1 16 package org.roller.presentation.atomapi; 17 18 import java.io.File ; 19 import java.io.FileInputStream ; 20 import java.io.FileOutputStream ; 21 import java.io.InputStream ; 22 import java.sql.Timestamp ; 23 import java.text.SimpleDateFormat ; 24 import java.util.ArrayList ; 25 import java.util.Date ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.StringTokenizer ; 29 30 import javax.servlet.http.HttpServletRequest ; 31 32 import org.apache.commons.logging.Log; 33 import org.apache.commons.logging.LogFactory; 34 import org.apache.struts.util.RequestUtils; 35 import org.roller.model.FileManager; 36 import org.roller.model.Roller; 37 import org.roller.model.WeblogManager; 38 import org.roller.pojos.UserData; 39 import org.roller.pojos.WeblogCategoryData; 40 import org.roller.pojos.WeblogEntryData; 41 import org.roller.pojos.WebsiteData; 42 import org.roller.presentation.LoginServlet; 43 import org.roller.presentation.RollerContext; 44 import org.roller.util.RollerMessages; 45 import org.roller.util.Utilities; 46 47 import com.sun.syndication.feed.atom.Content; 48 import com.sun.syndication.feed.atom.Entry; 49 import com.sun.syndication.feed.atom.Link; 50 import com.sun.syndication.io.impl.Base64; 51 52 81 public class RollerAtomHandler implements AtomHandler 82 { 83 private HttpServletRequest mRequest; 84 private Roller mRoller; 85 private RollerContext mRollerContext; 86 private String mUsername; 87 private int mMaxEntries = 20; 88 91 private static Log mLogger = 92 LogFactory.getFactory().getInstance(RollerAtomHandler.class); 93 94 private SimpleDateFormat timestampFormat = 95 new SimpleDateFormat ("yyyyMMddHHmmss" ); 96 97 99 104 public RollerAtomHandler(HttpServletRequest request) 105 { 106 mRequest = request; 107 mRoller = RollerContext.getRoller(request); 108 mRollerContext = RollerContext.getRollerContext(request); 109 110 mUsername = authenticateWSSE(request); 112 114 if (mUsername != null) 115 { 116 try 117 { 118 UserData user = mRoller.getUserManager().getUser(mUsername); 119 mRoller.setUser(user); 120 } 121 catch (Exception e) 122 { 123 mLogger.error("ERROR: setting user", e); 124 } 125 } 126 } 135 136 139 public String getAuthenticatedUsername() 140 { 141 return mUsername; 142 } 143 144 146 151 public AtomService getIntrospection(String [] pathInfo) throws Exception 152 { 153 if (pathInfo.length == 1) 154 { 155 String username = pathInfo[0]; 156 String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest); 157 158 AtomService service = new AtomService(); 159 160 AtomService.Workspace workspace = new AtomService.Workspace(); 161 workspace.setTitle("Workspace: Collections for " + username); 162 service.addWorkspace(workspace); 163 164 AtomService.Collection entryCol = new AtomService.Collection(); 165 entryCol.setTitle("Collection: Weblog Entries for " + username); 166 entryCol.setContents("entries"); 167 entryCol.setHref(absUrl + "/atom/"+mUsername+"/entries"); 168 workspace.addCollection(entryCol); 169 170 AtomService.Collection catCol = new AtomService.Collection(); 171 catCol.setTitle("Collection: Categories for " + username); 172 catCol.setContents("categories"); 173 catCol.setHref(absUrl + "/atom/"+mUsername+"/categories"); 174 workspace.addCollection(catCol); 175 176 AtomService.Collection uploadCol = new AtomService.Collection(); 177 uploadCol.setTitle("Collection: File uploads for " + username); 178 uploadCol.setContents("generic"); 179 uploadCol.setHref(absUrl + "/atom/"+mUsername+"/resources"); 180 workspace.addCollection(uploadCol); 181 182 return service; 183 } 184 throw new Exception ("ERROR: bad URL in getIntrospection()"); 185 } 186 187 189 193 public AtomCollection getCollection(String [] pathInfo) throws Exception 194 { 195 return getCollection(pathInfo, null, new Date (), -1); 196 } 197 198 212 public AtomCollection getCollection( 213 String [] pathInfo, Date start, Date end, int offset) 214 throws Exception 215 { 216 if (pathInfo.length > 0 && pathInfo[1].equals("entries")) 217 { 218 return getCollectionOfEntries(pathInfo, start, end, offset); 219 } 220 else if (pathInfo.length > 0 && pathInfo[1].equals("resources")) 221 { 222 return getCollectionOfResources(pathInfo, start, end, offset); 223 } 224 else if (pathInfo.length > 0 && pathInfo[1].equals("categories")) 225 { 226 return getCollectionOfCategories(pathInfo, start, end, offset); 227 } 228 throw new Exception ("ERROR: bad URL in getCollection()"); 229 } 230 231 234 public AtomCollection getCollectionOfEntries( 235 String [] pathInfo, Date start, Date end, int offset) 236 throws Exception 237 { 238 String username = pathInfo[0]; 239 String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest); 240 WebsiteData website = mRoller.getUserManager().getWebsite(username); 241 List entries = null; 242 if (canView(website)) 243 { 244 if (pathInfo.length == 2) { 246 if (offset == -1) 248 { 249 entries = mRoller.getWeblogManager().getWeblogEntries( 250 website, start, end, null, WeblogManager.ALL, new Integer (mMaxEntries + 1)); } 257 else 258 { 259 entries = mRoller.getWeblogManager().getWeblogEntries( 260 website, start, end, null, WeblogManager.ALL, offset, mMaxEntries + 1); } 268 } 269 else if (pathInfo.length == 3) { 271 String entryid = pathInfo[2]; 273 WeblogManager wmgr = mRoller.getWeblogManager(); 274 WeblogEntryData entry = wmgr.retrieveWeblogEntry(entryid); 275 entries = wmgr.getPreviousEntries(entry, null, mMaxEntries + 1); 276 } 277 else throw new Exception ("ERROR: bad URL"); 278 279 AtomCollection col = new AtomCollection(); 281 if (entries.size() > mMaxEntries) 282 { 283 WeblogEntryData lastEntry = 285 (WeblogEntryData)entries.get(entries.size() - 1); 286 col.setNext(createNextLink(lastEntry, start, end, offset)); 287 } 288 int count = 0; 290 Iterator iter = entries.iterator(); 291 while (iter.hasNext() && count++ < mMaxEntries) 292 { 293 WeblogEntryData rollerEntry = (WeblogEntryData)iter.next(); 294 AtomCollection.Member member = new AtomCollection.Member(); 295 member.setTitle(rollerEntry.getDisplayTitle()); 296 member.setUpdated(rollerEntry.getUpdateTime()); 297 member.setHref(absUrl 298 + "/atom/" + username + "/entry/" + rollerEntry.getId()); 299 col.addMember(member); 300 } 301 return col; 302 } 303 throw new Exception ("ERROR: not authorized"); 304 } 305 306 309 public AtomCollection getCollectionOfResources( 310 String [] pathInfo, Date start, Date end, int offset) throws Exception 311 { 312 String username = pathInfo[0]; 313 String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest); 314 WebsiteData website = mRoller.getUserManager().getWebsite(username); 315 FileManager fmgr = mRoller.getFileManager(); 316 File [] files = fmgr.getFiles(website); 317 if (canView(website)) 318 { 319 AtomCollection col = new AtomCollection(); 320 for (int i=0; i<files.length; i++) 321 { 322 AtomCollection.Member member = new AtomCollection.Member(); 323 member.setTitle(files[i].getName()); 324 member.setUpdated(new Date (files[i].lastModified())); 325 member.setHref(absUrl 326 + "/atom/" + username + "/resource/" + files[i].getName() ); 327 col.addMember(member); 328 } 329 return col; 330 } 331 throw new Exception ("ERROR: not authorized"); 332 } 333 334 337 public AtomCollection getCollectionOfCategories( 338 String [] pathInfo, Date start, Date end, int offset) throws Exception 339 { 340 String username = pathInfo[0]; 341 String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest); 342 WebsiteData website = mRoller.getUserManager().getWebsite(username); 343 WeblogManager wmgr = mRoller.getWeblogManager(); 344 List items = wmgr.getWeblogCategories(website); 345 if (canView(website)) 346 { 347 AtomCollection col = new AtomCollection(); 348 Iterator iter = items.iterator(); 349 Date now = new Date (); 350 while (iter.hasNext()) 351 { 352 WeblogCategoryData item = (WeblogCategoryData)iter.next(); 353 AtomCollection.Member member = new AtomCollection.Member(); 354 member.setTitle(item.getPath()); 355 member.setUpdated(now); 356 member.setHref( 357 absUrl + "/atom/" + username + "/category/" + item.getId()); 358 col.addMember(member); 359 } 360 return col; 361 } 362 throw new Exception ("ERROR: not authorized"); 363 } 364 365 367 370 public Entry postEntry(String [] pathInfo, Entry entry) throws Exception 371 { 372 String username = pathInfo[0]; 374 WebsiteData website = mRoller.getUserManager().getWebsite(username); 375 if (canEdit(website)) 376 { 377 WeblogEntryData rollerEntry = createRollerEntry(website, entry); 379 rollerEntry.save(); 380 mRoller.commit(); 381 382 Thread.sleep(1000); 385 386 390 return createAtomEntry(rollerEntry); 391 } 392 throw new Exception ("ERROR not authorized to edit website"); 393 } 394 395 398 public Entry getEntry(String [] pathInfo) throws Exception 399 { 400 if (pathInfo.length == 3) { 402 WeblogEntryData entry = 403 mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]); 404 if (!canView(entry)) 405 { 406 throw new Exception ("ERROR not authorized to view entry"); 407 } 408 else if (entry != null) 409 { 410 return createAtomEntry(entry); 411 } 412 throw new Exception ("ERROR: entry not found"); 413 } 414 throw new Exception ("ERROR: bad URI"); 415 } 416 417 420 public Entry putEntry(String [] pathInfo, Entry entry) throws Exception 421 { 422 if (pathInfo.length == 3) { 424 WeblogEntryData rollerEntry = 425 mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]); 426 if (canEdit(rollerEntry)) 427 { 428 rollerEntry.setTitle(entry.getTitle()); 429 rollerEntry.setText(((Content)entry.getContents().get(0)).getValue()); 430 rollerEntry.setUpdateTime(new Timestamp (new Date ().getTime())); 431 rollerEntry.save(); 432 mRoller.commit(); 433 return createAtomEntry(rollerEntry); 434 } 435 throw new Exception ("ERROR not authorized to put entry"); 436 } 437 throw new Exception ("ERROR: bad URI"); 438 } 439 440 443 public void deleteEntry(String [] pathInfo) throws Exception 444 { 445 if (pathInfo.length == 3) { 447 WeblogEntryData rollerEntry = 448 mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]); 449 if (canEdit(rollerEntry)) 450 { 451 rollerEntry.remove(); 452 mRoller.commit(); 453 return; 454 } 455 throw new Exception ("ERROR not authorized to delete entry"); 456 } 457 throw new Exception ("ERROR: bad URI"); 458 } 459 460 462 468 public String postResource(String [] pathInfo, 469 String name, String contentType, InputStream is) 470 throws Exception 471 { 472 String username = pathInfo[0]; 474 WebsiteData website = mRoller.getUserManager().getWebsite(username); 475 if (canEdit(website) && pathInfo.length > 1) 476 { 477 try 478 { 479 FileManager fmgr = mRoller.getFileManager(); 480 RollerMessages msgs = new RollerMessages(); 481 482 if (name == null) 484 { 485 throw new Exception ( 486 "ERROR[postResource]: No 'name' present in HTTP headers"); 487 } 488 File tempFile = File.createTempFile(name,"tmp"); 489 FileOutputStream fos = new FileOutputStream (tempFile); 490 Utilities.copyInputToOutput(is, fos); 491 fos.close(); 492 493 if (fmgr.canSave(website, name, tempFile.length(), msgs)) 495 { 496 FileInputStream fis = new FileInputStream (tempFile); 498 fmgr.saveFile(website, name, tempFile.length(), fis); 499 fis.close(); 500 501 String uploadPath = RollerContext.getUploadPath( 503 mRequest.getSession(true).getServletContext()); 504 uploadPath += "/" + website.getUser().getUserName() + "/" + name; 505 return RequestUtils.printableURL( 506 RequestUtils.absoluteURL(mRequest, uploadPath)); 507 } 508 tempFile.delete(); 509 throw new Exception ("File upload denied because:" + msgs.toString()); 510 } 511 catch (Exception e) 512 { 513 String msg = "ERROR in atom.postResource"; 514 mLogger.error(msg,e); 515 throw new Exception (msg); 516 } 517 } 518 throw new Exception ("ERROR not authorized to edit website"); 519 } 520 521 524 public String getResourceFilePath(String [] pathInfo) throws Exception 525 { 526 String uploadPath = RollerContext.getUploadPath( 528 mRequest.getSession(true).getServletContext()); 529 return uploadPath + File.separator + pathInfo[2]; 530 } 531 532 536 public void putResource(String [] pathInfo, 537 String contentType, InputStream is) throws Exception 538 { 539 if (pathInfo.length > 2) 540 { 541 String name = pathInfo[2]; 542 postResource(pathInfo, name, contentType, is); 543 } 544 throw new Exception ("ERROR: bad pathInfo"); 545 } 546 547 551 public void deleteResource(String [] pathInfo) throws Exception 552 { 553 String username = pathInfo[0]; 555 WebsiteData website = mRoller.getUserManager().getWebsite(username); 556 if (canEdit(website) && pathInfo.length > 1) 557 { 558 try 559 { 560 FileManager fmgr = mRoller.getFileManager(); 561 fmgr.deleteFile(website, pathInfo[2]); 562 } 563 catch (Exception e) 564 { 565 String msg = "ERROR in atom.deleteResource"; 566 mLogger.error(msg,e); 567 throw new Exception (msg); 568 } 569 } 570 throw new Exception ("ERROR not authorized to edit website"); 571 } 572 573 575 578 public boolean isIntrospectionURI(String [] pathInfo) 579 { 580 if (pathInfo.length == 1 && pathInfo[0].equals(mUsername)) return true; 581 return false; 582 } 583 584 587 public boolean isEntryURI(String [] pathInfo) 588 { 589 if (pathInfo.length > 1 && pathInfo[1].equals("entry")) return true; 590 return false; 591 } 592 593 596 public boolean isResourceURI(String [] pathInfo) 597 { 598 if (pathInfo.length > 1 && pathInfo[1].equals("resource")) return true; 599 return false; 600 } 601 602 605 public boolean isCategoryURI(String [] pathInfo) 606 { 607 if (pathInfo.length > 1 && pathInfo[1].equals("category")) return true; 608 return false; 609 } 610 611 614 public boolean isCollectionURI(String [] pathInfo) 615 { 616 if (pathInfo.length > 1 && pathInfo[1].equals("entries")) return true; 617 if (pathInfo.length > 1 && pathInfo[1].equals("resources")) return true; 618 if (pathInfo.length > 1 && pathInfo[1].equals("categories")) return true; 619 return false; 620 } 621 622 625 public boolean isEntryCollectionURI(String [] pathInfo) 626 { 627 if (pathInfo.length > 1 && pathInfo[1].equals("entries")) return true; 628 return false; 629 } 630 631 634 public boolean isResourceCollectionURI(String [] pathInfo) 635 { 636 if (pathInfo.length > 1 && pathInfo[1].equals("resources")) return true; 637 return false; 638 } 639 640 643 public boolean isCategoryCollectionURI(String [] pathInfo) 644 { 645 if (pathInfo.length > 1 && pathInfo[1].equals("categories")) return true; 646 return false; 647 } 648 649 651 654 private boolean canEdit(WeblogEntryData entry) 655 { 656 return entry.getWebsite().getUser().getUserName().equals(mUsername); 657 } 658 659 662 private boolean canEdit(WebsiteData website) 663 { 664 return website.getUser().getUserName().equals(mUsername); 665 } 666 667 670 private boolean canView(WeblogEntryData entry) 671 { 672 return canEdit(entry); 673 } 674 675 678 private boolean canView(WebsiteData website) 679 { 680 return canEdit(website); 681 } 682 683 685 689 protected String authenticateWSSE(HttpServletRequest request) 690 { 691 String wsseHeader = request.getHeader("X-WSSE"); 692 if (wsseHeader == null) return null; 693 694 String ret = null; 695 String userName = null; 696 String created = null; 697 String nonce = null; 698 String passwordDigest = null; 699 String [] tokens = wsseHeader.split(","); 700 for (int i = 0; i < tokens.length; i++) 701 { 702 int index = tokens[i].indexOf('='); 703 if (index != -1) 704 { 705 String key = tokens[i].substring(0, index).trim(); 706 String value = tokens[i].substring(index + 1).trim(); 707 value = value.replaceAll("\"", ""); 708 if (key.startsWith("UsernameToken")) 709 { 710 userName = value; 711 } 712 else if (key.equalsIgnoreCase("nonce")) 713 { 714 nonce = value; 715 } 716 else if (key.equalsIgnoreCase("passworddigest")) 717 { 718 passwordDigest = value; 719 } 720 else if (key.equalsIgnoreCase("created")) 721 { 722 created = value; 723 } 724 } 725 } 726 String digest = null; 727 try 728 { 729 UserData user = mRoller.getUserManager().getUser(userName); 730 digest = WSSEUtilities.generateDigest( 731 WSSEUtilities.base64Decode(nonce), 732 created.getBytes("UTF-8"), 733 user.getPassword().getBytes("UTF-8")); 734 if (digest.equals(passwordDigest)) 735 { 736 ret = userName; 737 } 738 } 739 catch (Exception e) 740 { 741 mLogger.error("ERROR in wsseAuthenticataion: " + e.getMessage(), e); 742 } 743 return ret; 744 } 745 746 749 public String authenticateBASIC(HttpServletRequest request) 750 { 751 boolean valid = false; 752 String userID = null; 753 String password = null; 754 try 755 { 756 String authHeader = request.getHeader("Authorization"); 757 if (authHeader != null) 758 { 759 StringTokenizer st = new StringTokenizer (authHeader); 760 if (st.hasMoreTokens()) 761 { 762 String basic = st.nextToken(); 763 if (basic.equalsIgnoreCase("Basic")) 764 { 765 String credentials = st.nextToken(); 766 String userPass = new String (Base64.decode(credentials)); 767 int p = userPass.indexOf(":"); 768 if (p != -1) 769 { 770 userID = userPass.substring(0, p); 771 UserData user = mRoller.getUserManager().getUser(userID); 772 String realpassword = LoginServlet.getEncryptedPassword( 773 request, user.getUserName(), user.getPassword()); 774 password = userPass.substring(p+1); 775 if ( (!userID.trim().equals(user.getUserName())) 776 && (!password.trim().equals(realpassword))) 777 { 778 valid = true; 779 } 780 } 781 } 782 } 783 } 784 } 785 catch (Exception e) 786 { 787 mLogger.debug(e); 788 } 789 if (valid) return userID; 790 return null; 791 } 792 793 795 799 private String createNextLink( 800 WeblogEntryData entry, Date start, Date end, int offset) 801 { 802 SimpleDateFormat df = new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ssZ" ); 803 String absUrl = mRollerContext.getAbsoluteContextUrl(); 804 String url = absUrl + "/atom/" + mUsername + "/entries/" + entry.getId(); 805 if (offset != -1 && start != null && end != null) 806 { 807 url = url + "?Range=" + df.format(start) + "/" + df.format(end); 808 } 809 else if (offset != -1 && start != null) 810 { 811 url = url + "?Range=" + df.format(start) + "/"; 812 } 813 else if (offset != -1 && end != null) 814 { 815 url = url + "?Range=/" + df.format(end); 816 } 817 if (offset != -1) 818 { 819 url = url + "&offset=" + (offset + mMaxEntries); 820 } 821 return url; 822 } 823 824 829 private Entry createAtomEntry(WeblogEntryData entry) 830 { 831 Entry atomEntry = new Entry(); 832 Content content = new Content(); 833 content.setMode(Content.ESCAPED); 834 content.setValue(entry.getText()); 835 List contents = new ArrayList (); 836 contents.add(content); 837 838 atomEntry.setId( entry.getId()); 839 atomEntry.setTitle( entry.getTitle()); 840 atomEntry.setContents( contents); 841 atomEntry.setIssued( entry.getPubTime()); 842 atomEntry.setModified( entry.getUpdateTime()); 843 844 List links = new ArrayList (); 845 Link altlink = new Link(); 846 altlink.setRel("alternate"); 847 altlink.setHref(entry.getPermaLink()); 848 links.add(altlink); 849 atomEntry.setAlternateLinks(links); 850 851 return atomEntry; 852 } 853 854 857 private WeblogEntryData createRollerEntry(WebsiteData website, Entry entry) 858 { 859 Timestamp current = new Timestamp (System.currentTimeMillis()); 860 Timestamp pubTime = current; 861 Timestamp updateTime = current; 862 if (entry.getIssued() != null) 863 { 864 pubTime = new Timestamp ( entry.getIssued().getTime() ); 865 } 866 if (entry.getModified() != null) 867 { 868 updateTime = new Timestamp ( entry.getModified().getTime() ); 869 } 870 WeblogEntryData rollerEntry = new WeblogEntryData(); 871 rollerEntry.setTitle(entry.getTitle()); 872 rollerEntry.setText( ((Content)entry.getContents().get(0)).getValue() ); 873 rollerEntry.setPubTime(pubTime); 874 rollerEntry.setUpdateTime(updateTime); 875 rollerEntry.setWebsite(website); 876 rollerEntry.setPublishEntry( Boolean.TRUE ); 877 rollerEntry.setCategory(website.getBloggerCategory()); 878 879 return rollerEntry; 880 } 881 } 882 | Popular Tags |