From b5738f7337c2732090388fb592c45b0edbee2d1d Mon Sep 17 00:00:00 2001
From: Nicholas Blair <nicholas.blair@wisc.edu>
Date: Mon, 16 May 2016 10:46:52 -0500
Subject: [PATCH] feat: add uw-frame compatible output for /profile/uw-frame

---
 .../edu/wisc/uwss/web/ProfileController.java  |  44 +++++-
 .../wisc/uwss/web/uwframe/UwframeBuild.java   | 113 +++++++++++++++
 .../wisc/uwss/web/uwframe/UwframeSession.java | 131 ++++++++++++++++++
 .../uwss/web/uwframe/UwframeBuildTest.java    |  50 +++++++
 .../uwss/web/uwframe/UwframeSessionTest.java  |  47 +++++++
 5 files changed, 381 insertions(+), 4 deletions(-)
 create mode 100644 uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeBuild.java
 create mode 100644 uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeSession.java
 create mode 100644 uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeBuildTest.java
 create mode 100644 uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeSessionTest.java

diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/ProfileController.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/ProfileController.java
index 8ec8233..cc1295c 100644
--- a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/ProfileController.java
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/ProfileController.java
@@ -3,16 +3,17 @@
  */
 package edu.wisc.uwss.web;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.core.Authentication;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
 import org.springframework.security.core.annotation.AuthenticationPrincipal;
-import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import edu.wisc.uwss.UWUserDetails;
+import edu.wisc.uwss.web.uwframe.UwframeSession;
+
 /**
  * {@link Controller} useful for returning the current authenticated principal.
  *
@@ -20,7 +21,11 @@ import org.springframework.web.bind.annotation.ResponseBody;
  * @author Nicholas Blair
  */
 @Controller
+@RequestMapping("/profile")
 public class ProfileController {
+  @Autowired
+  private Environment environment;
+
   /**
    * This method intentionally avoids using {@link edu.wisc.uwss.UWUserDetails} for the argument and
    * return type. Configurations exist that may result authentication not being required for this URL.
@@ -32,4 +37,35 @@ public class ProfileController {
     return principal;
   }
 
+  /**
+   * This method transforms the {@link UWUserDetails} (if present) to a {@link UwframeSession},
+   * Intended for use in uw-frame applications.
+   *
+   * To register this url in your uw-frame app, create the file 'src/main/webapp/js/override.js' with the following
+   * contents:
+   <pre>
+   define(['angular'], function(angular) {
+     var config = angular.module('override', []);
+     config
+       .constant('OVERRIDE', {
+         'SERVICE_LOC': {
+           'sessionInfo' : 'profile/uw-frame',
+         }
+     });
+     return config;
+   });
+   </pre>
+   *
+   * @param principal
+   * @return the current authenticated principal as a {@link UwframeSession}
+   */
+  @RequestMapping(value="/profile/uw-frame", method=RequestMethod.GET)
+  public @ResponseBody Object uwFrameCompatibleProfile(@AuthenticationPrincipal Object principal) {
+    if(principal instanceof UWUserDetails) {
+      return new UwframeSession(environment, (UWUserDetails) principal);
+    } else {
+      return new UwframeSession(environment);
+    }
+  }
+
 }
diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeBuild.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeBuild.java
new file mode 100644
index 0000000..4ad0eab
--- /dev/null
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeBuild.java
@@ -0,0 +1,113 @@
+/**
+ * 
+ */
+package edu.wisc.uwss.web.uwframe;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Bean that mimics the data model uw-frame expects for the application's build information.
+ * 
+ * @author Nicholas Blair
+ */
+public class UwframeBuild {
+
+  protected String buildNumber;
+  protected String scmBranch;
+  protected String projectVersion;
+  protected String tags;
+
+  public UwframeBuild() {
+  }
+  /**
+   * 
+   * @param buildNumber the git commitId
+   * @param scmBranch the git branch (can be null)
+   * @param projectVersion the maven project version
+   * @param tags the tags (can be null)
+   */
+  public UwframeBuild(String buildNumber, String scmBranch, String projectVersion, String tags) {
+    this.buildNumber = buildNumber;
+    this.scmBranch = scmBranch;
+    this.projectVersion = projectVersion;
+    this.tags = tags;
+  }
+  /**
+   * @return the buildNumber
+   */
+  public String getBuildNumber() {
+    return buildNumber;
+  }
+  /**
+   * @param buildNumber the buildNumber to set
+   */
+  public UwframeBuild setBuildNumber(String buildNumber) {
+    this.buildNumber = buildNumber;
+    return this;
+  }
+  /**
+   * @return the scmBranch
+   */
+  public String getScmBranch() {
+    return scmBranch;
+  }
+  /**
+   * @param scmBranch the scmBranch to set
+   */
+  public UwframeBuild setScmBranch(String scmBranch) {
+    this.scmBranch = scmBranch;
+    return this;
+  }
+  /**
+   * @return the projectVersion
+   */
+  public String getProjectVersion() {
+    return projectVersion;
+  }
+  /**
+   * @param projectVersion the projectVersion to set
+   */
+  public UwframeBuild setProjectVersion(String projectVersion) {
+    this.projectVersion = projectVersion;
+    return this;
+  }
+
+  /**
+   * @return the tags
+   */
+  public String getTags() {
+    return tags;
+  }
+  /**
+   * @param tags the tags to set
+   */
+  public UwframeBuild setTags(String tags) {
+    this.tags = tags;
+    return this;
+  }
+
+  /**
+   * Returns an empty string if not all necessary fields are set.
+   *
+   * @return the fields as a single, human readable string
+   */
+  public String toVersionString() {
+    if(StringUtils.isBlank(buildNumber)) {
+      return "";
+    }
+    StringBuilder builder = new StringBuilder();
+    builder.append("Revision ");
+    builder.append(buildNumber);
+    if(StringUtils.isNotBlank(projectVersion)) {
+      builder.append(" (Version ");
+      builder.append(projectVersion);
+      if (StringUtils.isBlank(tags) && StringUtils.isNotBlank(scmBranch)) {
+        builder.append(" from ");
+        builder.append(scmBranch);
+        builder.append(" branch");
+      }
+      builder.append(")");
+    }
+    return builder.toString();
+  }
+}
diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeSession.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeSession.java
new file mode 100644
index 0000000..665f5ba
--- /dev/null
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/uwframe/UwframeSession.java
@@ -0,0 +1,131 @@
+package edu.wisc.uwss.web.uwframe;
+
+import org.springframework.core.env.Environment;
+
+import edu.wisc.uwss.UWUserDetails;
+
+/**
+ * Bean matching data model expected by <a href="https://github.com/UW-Madison-DoIT/uw-frame">uw-frame</a>.
+ *
+ * The session contains a mix of user attributes and product revision information:
+ *
+ <pre>
+ {
+   "person": {
+     "userName": "admin",
+     "sessionKey": "someRandomKey",
+     "serverName": "localhost",
+     "firstName" : "Bucky",
+     "lastName" : "Badger",
+     "displayName": "Bucky Badger",
+     "email" : "bucky@wisc.edu",
+     "version": "2.2.0"
+   }
+ }
+ </pre>
+ *
+ * @author Nicholas Blair
+ */
+public class UwframeSession {
+
+  public static final String GIT_BRANCH = "git.branch";
+  public static final String GIT_COMMIT_ID_ABBREV = "git.commit.id.abbrev";
+  public static final String GIT_TAGS = "git.tags";
+  public static final String PROJECT_VERSION = "projectVersion";
+
+  private final String username;
+  private final String displayName;
+  private final String firstName;
+  private final String lastName;
+  private final UwframeBuild build;
+
+  /**
+   * Construct a "guest" session with no revision information available.
+   */
+  public UwframeSession() {
+    this(null);
+  }
+  /**
+   * Construct a "guest" session
+   *
+   * @param environment source for revision information
+   */
+  public UwframeSession(Environment environment) {
+    this(environment, "anonymousUser", "Guest", "Guest", "");
+  }
+  /**
+   * Preferred constructor.
+   *
+   * @param environment
+   * @param userDetails
+   */
+  public UwframeSession(Environment environment, UWUserDetails userDetails) {
+    this(environment, userDetails.getUsername(), userDetails.getFullName(), userDetails.getFirstName(), userDetails.getLastName());
+  }
+  /**
+   *
+   * @param environment
+   * @param username
+   * @param displayName
+   * @deprecated prefer constructor UwframeSession(Environment, UWUserDetails) instead
+   */
+  @Deprecated
+  public UwframeSession(Environment environment, String username, String displayName) {
+    this(environment, username, displayName, null, null);
+  }
+
+  public UwframeSession(Environment environment, String username, String displayName, String firstName, String lastName) {
+    this.username = username;
+    this.displayName = displayName;
+    this.firstName = firstName;
+    this.lastName = lastName;
+    if(environment != null && environment.containsProperty(GIT_COMMIT_ID_ABBREV)) {
+      this.build =  new UwframeBuild(environment.getProperty(GIT_COMMIT_ID_ABBREV), environment.getProperty(GIT_BRANCH), environment.getProperty(PROJECT_VERSION), environment.getProperty(GIT_TAGS));
+    } else {
+      this.build = new UwframeBuild();
+    }
+  }
+
+  /**
+   * @return the username
+   */
+  public String getUsername() {
+    return username;
+  }
+  /**
+   * @return always an empty String
+   */
+  public String getSessionKey() {
+    return "";
+  }
+  /**
+   * @return always an empty String
+   */
+  public String getServerName() {
+    return "";
+  }
+  /**
+   * @return the displayName
+   */
+  public String getDisplayName() {
+    return displayName;
+  }
+  /**
+   * @return the first name
+   */
+  public String getFirstName() {
+    return firstName;
+  }
+  /**
+   * @return the last name
+   */
+  public String getLastName() {
+    return lastName;
+  }
+  /**
+   * @return the version
+   */
+  public String getVersion() {
+    return build.toVersionString();
+  }
+}
diff --git a/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeBuildTest.java b/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeBuildTest.java
new file mode 100644
index 0000000..2532a1f
--- /dev/null
+++ b/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeBuildTest.java
@@ -0,0 +1,50 @@
+package edu.wisc.uwss.web.uwframe;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link UwframeBuild}
+ * @author Nicholas Blair
+ */
+public class UwframeBuildTest {
+
+  @Test
+  public void toVersionString_empty() {
+    assertEquals("", new UwframeBuild().toVersionString());
+  }
+
+  @Test
+  public void toVersionString_revisionOnly() {
+    assertEquals("Revision abcde1", new UwframeBuild().setBuildNumber("abcde1").toVersionString());
+  }
+  @Test
+  public void toVersionString_release_withbranch() {
+    assertEquals("Revision abcde1 (Version 1.2.3 from release-1-2 branch)",
+            new UwframeBuild()
+                    .setBuildNumber("abcde1")
+                    .setProjectVersion("1.2.3")
+                    .setScmBranch("release-1-2")
+                    .toVersionString());
+  }
+  @Test
+  public void toVersionString_release_withtag() {
+    assertEquals("Revision abcde1 (Version 1.2.3)",
+            new UwframeBuild()
+                    .setBuildNumber("abcde1")
+                    .setProjectVersion("1.2.3")
+                    .setTags("1.2.3")
+                    .setScmBranch("feature-branch")
+                    .toVersionString());
+  }
+  @Test
+  public void toVersionString_complete() {
+    assertEquals("Revision abcde1 (Version 1.2.3-SNAPSHOT from feature-branch branch)",
+            new UwframeBuild()
+                    .setBuildNumber("abcde1")
+                    .setProjectVersion("1.2.3-SNAPSHOT")
+                    .setScmBranch("feature-branch")
+                    .toVersionString());
+  }
+}
diff --git a/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeSessionTest.java b/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeSessionTest.java
new file mode 100644
index 0000000..7f47c7f
--- /dev/null
+++ b/uw-spring-security-web/src/test/java/edu/wisc/uwss/web/uwframe/UwframeSessionTest.java
@@ -0,0 +1,47 @@
+package edu.wisc.uwss.web.uwframe;
+
+import org.junit.Test;
+import org.springframework.core.env.Environment;
+import org.springframework.mock.env.MockEnvironment;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link UwframeSession}.
+ *
+ * @author Nicholas Blair
+ */
+public class UwframeSessionTest {
+
+  @Test
+  public void empty() {
+    UwframeSession session = new UwframeSession();
+    assertEquals("anonymousUser", session.getUsername());
+    assertEquals("Guest", session.getDisplayName());
+    assertEquals("Guest", session.getFirstName());
+    assertEquals("", session.getLastName());
+    assertEquals("", session.getVersion());
+  }
+
+  @Test
+  public void with_empty_Environment() {
+    Environment environment = new MockEnvironment();
+    UwframeSession session = new UwframeSession(environment, "jim", "James Badger", "James", "Badger");
+    assertEquals("jim", session.getUsername());
+    assertEquals("James Badger", session.getDisplayName());
+    assertEquals("James", session.getFirstName());
+    assertEquals("Badger", session.getLastName());
+    assertEquals("", session.getVersion());
+  }
+  @Test
+  public void with_complete_Environment() {
+    MockEnvironment environment = new MockEnvironment();
+    environment.setProperty(UwframeSession.GIT_COMMIT_ID_ABBREV, "abcde2");
+    UwframeSession session = new UwframeSession(environment, "jim", "James Badger", "James", "Badger");
+    assertEquals("jim", session.getUsername());
+    assertEquals("James Badger", session.getDisplayName());
+    assertEquals("James", session.getFirstName());
+    assertEquals("Badger", session.getLastName());
+    assertEquals("Revision abcde2", session.getVersion());
+  }
+}
-- 
GitLab