Adding GUI login/logout capability using form-based login.

Adding REST API login capability using basic authentication.

HTTP to HTTPS redirect is suppressed for now.

Change-Id: I1a98bdc5576c515e1aa5a1b8d66402af0c0bf8c8
diff --git a/tools/package/bin/onos-secure-ssh b/tools/package/bin/onos-secure-ssh
index 6c46904..ac94de5 100755
--- a/tools/package/bin/onos-secure-ssh
+++ b/tools/package/bin/onos-secure-ssh
@@ -7,6 +7,17 @@
 
 set -e
 
+# Scan argument for user/password or other options...
+while getopts u:p: o; do
+    case "$o" in
+        u) user=$OPTARG;;
+        p) password=$OPTARG;;
+    esac
+done
+password=${password:-user} # password defaults to the user name if not specified
+let OPC=$OPTIND-1
+shift $OPC
+
 cd $(dirname $0)/../apache-karaf-*/etc
 USERS=users.properties
 KEYS=keys.properties
@@ -18,5 +29,10 @@
 # Remove any previous known keys for the local host.
 ssh-keygen -f "$HOME/.ssh/known_hosts" -R [localhost]:8101
 
-# Swap the onos client to use the SSH variant
+# Swap the onos client to use the SSH variant.
 ln -s $(dirname $0)/onos-ssh $(dirname $0)/onos
+
+# If user and password options were given, setup the user/password.
+if [ -n "$user" -a -n "$password" ]; then
+    echo "$user = $password,_g_:admingroup" >> $USERS
+fi
\ No newline at end of file
diff --git a/tools/package/etc/org.ops4j.pax.web.cfg b/tools/package/etc/org.ops4j.pax.web.cfg
new file mode 100644
index 0000000..c8fb3b3
--- /dev/null
+++ b/tools/package/etc/org.ops4j.pax.web.cfg
@@ -0,0 +1,12 @@
+org.osgi.service.http.port=8181
+org.osgi.service.http.port.secure=8443
+
+org.osgi.service.http.enabled=true
+org.osgi.service.http.secure.enabled=false
+
+org.ops4j.pax.web.ssl.keystore=etc/keystore
+org.ops4j.pax.web.ssl.password=OBF:1xtn1w1u1uob1xtv1y7z1xtn1unn1w1o1xtv
+org.ops4j.pax.web.ssl.keypassword=OBF:1xtn1w1u1uob1xtv1y7z1xtn1unn1w1o1xtv
+
+org.ops4j.pax.web.session.url=none
+org.ops4j.pax.web.config.file=./etc/jetty.xml
diff --git a/tools/test/bin/onos-secure-ssh b/tools/test/bin/onos-secure-ssh
index 1ec0bff..3c15fa3 100755
--- a/tools/test/bin/onos-secure-ssh
+++ b/tools/test/bin/onos-secure-ssh
@@ -19,7 +19,7 @@
     ssh $ONOS_USER@$node "
         [ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' -q
         $ONOS_INSTALL_DIR/bin/onos-user-key \$(id -un) \$(cut -d\\  -f2 ~/.ssh/id_rsa.pub)
-        $ONOS_INSTALL_DIR/bin/onos-secure-ssh
+        $ONOS_INSTALL_DIR/bin/onos-secure-ssh "$@"
 
         # Implicitly accept the new server key in dev/test environments
         while ! ssh -p 8101 -o StrictHostKeyChecking=no localhost list 2>/dev/null; do
diff --git a/tools/test/scenarios/setup.xml b/tools/test/scenarios/setup.xml
index 740260f..bcc65d9 100644
--- a/tools/test/scenarios/setup.xml
+++ b/tools/test/scenarios/setup.xml
@@ -16,7 +16,7 @@
 <scenario name="setup" description="ONOS cluster setup">
     <group name="Setup">
         <step name="Push-Bits" exec="onos-push-bits-through-proxy" if="${OCT}"/>
-        <step name="Secure-SSH" exec="onos-secure-ssh" if="${ONOS_USE_SSH}"/>
+        <step name="Secure-SSH" exec="onos-secure-ssh -u onos -p rocks" if="${ONOS_USE_SSH}"/>
 
         <parallel var="${OC#}">
             <step name="Push-Bits-${#}" exec="onos-push-bits ${OC#}"
diff --git a/web/api/src/main/webapp/WEB-INF/web.xml b/web/api/src/main/webapp/WEB-INF/web.xml
index 06f80da..fd4b0f7 100644
--- a/web/api/src/main/webapp/WEB-INF/web.xml
+++ b/web/api/src/main/webapp/WEB-INF/web.xml
@@ -21,30 +21,26 @@
     <display-name>ONOS REST API v1.0</display-name>
 
     <!--
+    -->
     <security-constraint>
-        <display-name>authenticated</display-name>
         <web-resource-collection>
-            <web-resource-name>All files</web-resource-name>
-            <description/>
+            <web-resource-name>Secured</web-resource-name>
             <url-pattern>/*</url-pattern>
         </web-resource-collection>
         <auth-constraint>
-            <description/>
             <role-name>admin</role-name>
         </auth-constraint>
     </security-constraint>
 
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+
     <login-config>
         <auth-method>BASIC</auth-method>
         <realm-name>karaf</realm-name>
     </login-config>
 
-    <security-role>
-        <description/>
-        <role-name>admin</role-name>
-    </security-role>
-    -->
-
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
diff --git a/web/gui/pom.xml b/web/gui/pom.xml
index 658bf19..4ce7e93 100644
--- a/web/gui/pom.xml
+++ b/web/gui/pom.xml
@@ -73,6 +73,8 @@
                         <_wab>src/main/webapp/</_wab>
                         <Include-Resource>
                             WEB-INF/classes/index.html=src/main/webapp/index.html,
+                            WEB-INF/classes/login.html=src/main/webapp/login.html,
+                            WEB-INF/classes/error.html=src/main/webapp/error.html,
                             WEB-INF/classes/not-ready.html=src/main/webapp/not-ready.html,
                             WEB-INF/classes/onos.js=src/main/webapp/onos.js,
                             WEB-INF/classes/nav.html=src/main/webapp/nav.html,
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/LogoutResource.java b/web/gui/src/main/java/org/onosproject/ui/impl/LogoutResource.java
new file mode 100644
index 0000000..b21b5cd
--- /dev/null
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/LogoutResource.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ui.impl;
+
+import org.onlab.rest.BaseResource;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Application upload resource.
+ */
+@Path("logout")
+public class LogoutResource extends BaseResource {
+
+    @Context
+    private HttpServletRequest servletRequest;
+
+    @GET
+    public Response logout() throws IOException, URISyntaxException {
+        servletRequest.getSession().invalidate();
+        String url = servletRequest.getRequestURL().toString();
+        url = url.replaceFirst("/onos/ui/.*", "/onos/ui/login.html");
+        return Response.temporaryRedirect(new URI(url)).build();
+    }
+
+}
diff --git a/web/gui/src/main/webapp/WEB-INF/web.xml b/web/gui/src/main/webapp/WEB-INF/web.xml
index f03925b..dda59f5 100644
--- a/web/gui/src/main/webapp/WEB-INF/web.xml
+++ b/web/gui/src/main/webapp/WEB-INF/web.xml
@@ -14,7 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          id="ONOS" version="2.5">
@@ -25,38 +26,44 @@
     </welcome-file-list>
 
     <!--
+    -->
     <security-constraint>
-        <display-name>authenticated</display-name>
         <web-resource-collection>
-            <web-resource-name>All files</web-resource-name>
-            <description/>
-            <url-pattern>/*</url-pattern>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/index.html</url-pattern>
         </web-resource-collection>
         <auth-constraint>
-            <description/>
             <role-name>admin</role-name>
         </auth-constraint>
+        <!--
+        <user-data-constraint>
+            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+        </user-data-constraint>
+        -->
     </security-constraint>
 
-    <login-config>
-        <auth-method>BASIC</auth-method>
-        <realm-name>karaf</realm-name>
-    </login-config>
-
     <security-role>
-        <description/>
         <role-name>admin</role-name>
     </security-role>
-    -->
 
-    <!--
-    -->
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>karaf</realm-name>
+        <form-login-config>
+            <form-login-page>/login.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
     <servlet>
         <servlet-name>Index Page</servlet-name>
-        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
+        </servlet-class>
         <init-param>
-            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
-            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass
+            </param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig
+            </param-value>
         </init-param>
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
@@ -68,19 +75,22 @@
     <servlet-mapping>
         <servlet-name>Index Page</servlet-name>
         <url-pattern>/index.html</url-pattern>
-        <url-pattern>/main.html</url-pattern>
     </servlet-mapping>
 
     <servlet>
         <servlet-name>Main Module</servlet-name>
-        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
+        </servlet-class>
         <init-param>
-            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
-            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass
+            </param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig
+            </param-value>
         </init-param>
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
-            <param-value>org.onosproject.ui.impl.MainModuleResource</param-value>
+            <param-value>org.onosproject.ui.impl.MainModuleResource
+            </param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>
     </servlet>
@@ -92,10 +102,13 @@
 
     <servlet>
         <servlet-name>Nav Module</servlet-name>
-        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
+        </servlet-class>
         <init-param>
-            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
-            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass
+            </param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig
+            </param-value>
         </init-param>
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
@@ -111,10 +124,13 @@
 
     <servlet>
         <servlet-name>View Module</servlet-name>
-        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
+        </servlet-class>
         <init-param>
-            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
-            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass
+            </param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig
+            </param-value>
         </init-param>
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
@@ -130,14 +146,18 @@
 
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
-        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
+        </servlet-class>
         <init-param>
-            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
-            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass
+            </param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig
+            </param-value>
         </init-param>
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
             <param-value>
+                org.onosproject.ui.impl.LogoutResource,
                 org.onosproject.ui.impl.TopologyResource,
                 org.onosproject.ui.impl.ApplicationResource
             </param-value>
@@ -152,7 +172,8 @@
 
     <servlet>
         <servlet-name>Web Socket Service</servlet-name>
-        <servlet-class>org.onosproject.ui.impl.UiWebSocketServlet</servlet-class>
+        <servlet-class>org.onosproject.ui.impl.UiWebSocketServlet
+        </servlet-class>
         <load-on-startup>2</load-on-startup>
     </servlet>
 
diff --git a/web/gui/src/main/webapp/app/fw/mast/mast.css b/web/gui/src/main/webapp/app/fw/mast/mast.css
index a9f3440..2e86e86 100644
--- a/web/gui/src/main/webapp/app/fw/mast/mast.css
+++ b/web/gui/src/main/webapp/app/fw/mast/mast.css
@@ -81,4 +81,22 @@
     padding-right: 16px;
     float: right;
     /*border: 1px solid red;*/
-}
\ No newline at end of file
+}
+
+#mast-right a {
+    font-size: 12pt;
+    font-style: normal;
+    font-weight: bold;
+    text-decoration: none;
+}
+
+.light #mast-right a {
+    color: #369;
+}
+.dark #mast-right a {
+    color: #eee;
+}
+
+#mast-right a:hover {
+    color: #CE5650;
+}
diff --git a/web/gui/src/main/webapp/app/fw/mast/mast.html b/web/gui/src/main/webapp/app/fw/mast/mast.html
index a5ddbc6..5bb488a 100644
--- a/web/gui/src/main/webapp/app/fw/mast/mast.html
+++ b/web/gui/src/main/webapp/app/fw/mast/mast.html
@@ -3,4 +3,4 @@
      ng-click="mastCtrl.toggleNav()"></div>
 <img class="logo" src="data/img/onos-logo.png">
 <span class="title">Open Network Operating System</span>
-<div id="mast-right"></div>
+<div id="mast-right"><a href="rs/logout">logout</a></div>
diff --git a/web/gui/src/main/webapp/data/img/onos-logo-fliprotate.png b/web/gui/src/main/webapp/data/img/onos-logo-fliprotate.png
new file mode 100644
index 0000000..7368017
--- /dev/null
+++ b/web/gui/src/main/webapp/data/img/onos-logo-fliprotate.png
Binary files differ
diff --git a/web/gui/src/main/webapp/data/img/onos-logo.lg.png b/web/gui/src/main/webapp/data/img/onos-logo.lg.png
new file mode 100644
index 0000000..afbd438
--- /dev/null
+++ b/web/gui/src/main/webapp/data/img/onos-logo.lg.png
Binary files differ
diff --git a/web/gui/src/main/webapp/error.html b/web/gui/src/main/webapp/error.html
new file mode 100644
index 0000000..564e284
--- /dev/null
+++ b/web/gui/src/main/webapp/error.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>ONOS Login</title>
+
+    <style type="text/css">
+        img {
+            margin: 24px;
+        }
+        td {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            text-align: left;
+            padding: 4px;
+        }
+        input {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            padding: 3px;
+        }
+
+        input[type="submit"] {
+            margin-top: 20px;
+            margin-left: auto;
+            margin-right: auto;
+            display: block;
+            padding: 4px 16px;
+            background-color: #CE5650;
+            color: #fff;
+            /*width: 100%; /!* width of image *!/*/
+            height: 32px;
+            border-radius: 3px;
+            border: 0;
+            -moz-outline-radius: 6px;
+        }
+
+        input[type="submit"]:hover {
+            border-radius: 3px;
+            border: 1px;
+            border-color: #fff;
+            border-style: solid;
+            box-shadow: 0px 0px 10px #3399ff;
+            outline-style: solid;
+            outline-width: 3px;
+            outline-color: #3399ff;
+        }
+
+        #error {
+            margin: 16px auto;
+            color: #CE5650;
+            text-align: center;
+
+        }
+    </style>
+</head>
+<body>
+<div align="center">
+    <img src="data/img/onos-logo.lg.png"/>
+
+    <form method="post" action="j_security_check">
+        <table>
+            <tr>
+                <td>User:</td>
+                <td><input id="username" name="j_username" type="text" autofocus/></td>
+            </tr>
+            <tr>
+                <td>Password:</td>
+                <td><input id="password" name="j_password" type="password"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><input id="submit" type="submit" value="Login"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><div id="error">Incorrect login credentials!</div></td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/login.html b/web/gui/src/main/webapp/login.html
new file mode 100644
index 0000000..d05260f
--- /dev/null
+++ b/web/gui/src/main/webapp/login.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>ONOS Login</title>
+
+    <style type="text/css">
+        img {
+            margin: 24px;
+        }
+        td {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            text-align: left;
+            padding: 4px;
+        }
+        input {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            padding: 3px;
+        }
+
+        input[type="submit"] {
+            margin-top: 20px;
+            margin-left: auto;
+            margin-right: auto;
+            display: block;
+            padding: 4px 16px;
+            background-color: #CE5650;
+            color: #fff;
+            /*width: 100%; /!* width of image *!/*/
+            height: 32px;
+            border-radius: 3px;
+            border: 0;
+            -moz-outline-radius: 6px;
+        }
+
+        input[type="submit"]:hover {
+            border-radius: 3px;
+            border: 1px;
+            border-color: #fff;
+            border-style: solid;
+            box-shadow: 0px 0px 10px #3399ff;
+            outline-style: solid;
+            outline-width: 3px;
+            outline-color: #3399ff;
+        }
+    </style>
+</head>
+<body>
+<div align="center">
+    <img src="data/img/onos-logo.lg.png"/>
+
+    <form method="post" action="j_security_check">
+        <table>
+            <tr>
+                <td>User:</td>
+                <td><input id="username" name="j_username" type="text" autofocus/></td>
+            </tr>
+            <tr>
+                <td>Password:</td>
+                <td><input id="password" name="j_password" type="password"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><input id="submit" type="submit" value="Login"/></td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>
\ No newline at end of file