From 36b7260f6bfac3686c963d4eb168a8ed977ef85b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 5 Sep 2010 13:54:49 +0200 Subject: [PATCH] added authentication demo --- .../sonia/scm/api/rest/SecurityFilter.java | 104 ++++++++++++++++++ .../resources/AuthenticationResource.java | 93 ++++++++++++++++ scm-webapp/src/main/webapp/index.html | 1 + .../src/main/webapp/resources/js/layout.js | 62 +++++++---- .../main/webapp/resources/js/sonia.group.js | 4 +- .../main/webapp/resources/js/sonia.login.js | 91 +++++++++++++++ 6 files changed, 334 insertions(+), 21 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/api/rest/SecurityFilter.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java create mode 100644 scm-webapp/src/main/webapp/resources/js/sonia.login.js 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