diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/SecurityFilter.java b/scm-webapp/src/main/java/sonia/scm/api/rest/SecurityFilter.java
new file mode 100644
index 0000000000..fd3b42d419
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/SecurityFilter.java
@@ -0,0 +1,104 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+
+package sonia.scm.api.rest;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@WebFilter(urlPatterns = "/api/rest/*")
+public class SecurityFilter implements Filter
+{
+
+ /** Field description */
+ public static final String URL_AUTHENTICATION = "/api/rest/authentication";
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ @Override
+ public void destroy()
+ {
+
+ // do nothing
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param req
+ * @param res
+ * @param chain
+ *
+ * @throws IOException
+ * @throws ServletException
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain)
+ throws IOException, ServletException
+ {
+ if ((req instanceof HttpServletRequest)
+ && (res instanceof HttpServletResponse))
+ {
+ HttpServletRequest request = (HttpServletRequest) req;
+ String uri =
+ request.getRequestURI().substring(request.getContextPath().length());
+
+ System.out.println( uri + "" + uri.startsWith( URL_AUTHENTICATION ) );
+
+ if (uri.startsWith(URL_AUTHENTICATION)
+ || (request.getSession(true).getAttribute("auth") != null))
+ {
+ chain.doFilter(req, res);
+ }
+ else
+ {
+ ((HttpServletResponse) res).sendError(
+ HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ }
+ else
+ {
+ throw new ServletException("request is not an HttpServletRequest");
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param filterConfig
+ *
+ * @throws ServletException
+ */
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+
+ // do nothing
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java
new file mode 100644
index 0000000000..70a71fbd5c
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java
@@ -0,0 +1,93 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+
+package sonia.scm.api.rest.resources;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.inject.Singleton;
+
+import javax.servlet.http.HttpServletRequest;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+@Path("authentication")
+@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+public class AuthenticationResource
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param username
+ * @param password
+ *
+ * @return
+ */
+ @POST
+ public Response authenticate(@Context HttpServletRequest request,
+ @FormParam("username") String username,
+ @FormParam("password") String password)
+ {
+ Response response = null;
+
+ if ("hans".equals(username) && "hans123".equals(password))
+ {
+ request.getSession(true).setAttribute("auth", Boolean.TRUE);
+ response = Response.ok().build();
+ }
+ else
+ {
+ response = Response.status(Response.Status.UNAUTHORIZED).build();
+ }
+
+ return response;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ *
+ * @return
+ */
+ @GET
+ public Response isAuthenticated(@Context HttpServletRequest request)
+ {
+ Response response = null;
+
+ if (request.getSession(true).getAttribute("auth") != null)
+ {
+ System.out.println( "authenticated" );
+
+ response = Response.ok().build();
+ }
+ else
+ {
+ response = Response.status(Response.Status.UNAUTHORIZED).build();
+ }
+
+ return response;
+ }
+}
diff --git a/scm-webapp/src/main/webapp/index.html b/scm-webapp/src/main/webapp/index.html
index 4190ccbbc8..a69c3e2fdb 100644
--- a/scm-webapp/src/main/webapp/index.html
+++ b/scm-webapp/src/main/webapp/index.html
@@ -13,6 +13,7 @@
+
diff --git a/scm-webapp/src/main/webapp/resources/js/layout.js b/scm-webapp/src/main/webapp/resources/js/layout.js
index 884683c169..641111ff9b 100644
--- a/scm-webapp/src/main/webapp/resources/js/layout.js
+++ b/scm-webapp/src/main/webapp/resources/js/layout.js
@@ -12,7 +12,20 @@ Ext.onReady(function(){
// should ensure that stable state ids are set for stateful components in real apps.
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
- var viewport = new Ext.Viewport({
+ var tabPanel = new Ext.TabPanel({
+ region: 'center', // a center region is ALWAYS required for border layout
+ deferredRender: false,
+ activeTab: 0, // first tab initially active
+ items: [{
+ id: 'welcome',
+ xtype: 'panel',
+ title: 'Welcome',
+ // closable: true,
+ autoScroll: true
+ }]
+ });
+
+ new Ext.Viewport({
layout: 'border',
items: [
// create instance immediately
@@ -47,7 +60,7 @@ Ext.onReady(function(){
iconCls: 'settings'
}]
},
- new Ext.BoxComponent({
+ new Ext.BoxComponent({
region: 'south',
id: 'south-panel',
contentEl: 'south',
@@ -57,24 +70,33 @@ Ext.onReady(function(){
// in this instance the TabPanel is not wrapped by another panel
// since no title is needed, this Panel is added directly
// as a Container
- new Ext.TabPanel({
- region: 'center', // a center region is ALWAYS required for border layout
- deferredRender: false,
- activeTab: 0, // first tab initially active
- items: [{
- id: 't_group',
- //contentEl: 'repository-tab',
- xtype: 'groupGrid',
- title: 'Groups',
- // closable: true,
- autoScroll: true
- }/*,{
- id: 't_repository',
- xtype: 'repositoryGrid',
- title: 'Repositories',
- autoScroll: true
- }*/]
- })]
+ tabPanel
+ ]});
+
+ function addGroupPanel(){
+ console.log( 'addGroupPanel' );
+ tabPanel.add({
+ id: 't_group',
+ xtype: 'groupGrid',
+ title: 'Groups',
+ closable: true,
+ autoScroll: true
+ });
+ }
+
+ Ext.Ajax.request({
+ url: restUrl + 'authentication.json',
+ method: 'GET',
+ success: function(){
+ addGroupPanel();
+ },
+ failure: function(){
+ var loginWin = new Sonia.login.Window();
+ loginWin.on('success', function(){
+ addGroupPanel();
+ });
+ loginWin.show();
+ }
});
});
\ No newline at end of file
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.group.js b/scm-webapp/src/main/webapp/resources/js/sonia.group.js
index c43f621a74..41f2ee9f27 100644
--- a/scm-webapp/src/main/webapp/resources/js/sonia.group.js
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.group.js
@@ -109,7 +109,7 @@ var groupStore = new Ext.data.JsonStore({
}
});
-groupStore.load();
+//groupStore.load();
Sonia.GroupGrid = Ext.extend(Ext.grid.GridPanel, {
initComponent: function(){
@@ -127,6 +127,8 @@ Sonia.GroupGrid = Ext.extend(Ext.grid.GridPanel, {
}
};
+ groupStore.load();
+
Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.GroupGrid.superclass.initComponent.apply(this, arguments);
}
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.login.js b/scm-webapp/src/main/webapp/resources/js/sonia.login.js
new file mode 100644
index 0000000000..e4a6263d5c
--- /dev/null
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.login.js
@@ -0,0 +1,91 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+Ext.ns('Sonia.login');
+
+Sonia.login.Form = Ext.extend(Ext.FormPanel,{
+
+ initComponent: function(){
+
+ var config = {
+ labelWidth:80,
+ url: restUrl + "authentication.json",
+ frame:true,
+ title:'Please Login',
+ defaultType:'textfield',
+ monitorValid:true,
+ items:[{
+ fieldLabel:'Username',
+ name:'username',
+ allowBlank:false
+ },{
+ fieldLabel:'Password',
+ name:'password',
+ inputType:'password',
+ allowBlank:false
+ }],
+ buttons:[{
+ text:'Login',
+ formBind: true,
+ scope: this,
+ handler: function(){
+ var form = this.getForm();
+ form.submit({
+ method:'POST',
+ waitTitle:'Connecting',
+ waitMsg:'Sending data...',
+
+ success: function(){
+ Ext.Msg.alert('Login Success!');
+ },
+
+ failure: function(form, action){
+ Ext.Msg.alert('Login Failure!');
+ form.reset();
+ }
+ });
+ }
+ }]
+ };
+
+ Ext.apply(this, Ext.apply(this.initialConfig, config));
+ Sonia.login.Form.superclass.initComponent.apply(this, arguments);
+
+ }
+
+});
+
+Ext.reg('soniaLoginForm', Sonia.login.Form);
+
+Sonia.login.Window = Ext.extend(Ext.Window,{
+
+ initComponent: function(){
+
+ var form = new Sonia.login.Form();
+ form.on('actioncomplete', function(){
+ this.fireEvent('success');
+ this.close();
+ }, this);
+
+ var config = {
+ layout:'fit',
+ width:300,
+ height:150,
+ closable: false,
+ resizable: false,
+ plain: true,
+ border: false,
+ modal: true,
+ items: [form]
+ };
+
+ this.addEvents('success');
+
+ Ext.apply(this, Ext.apply(this.initialConfig, config));
+ Sonia.login.Window.superclass.initComponent.apply(this, arguments);
+
+ }
+
+});
\ No newline at end of file