2 * Copyright 2011 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.webdav.milton;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 import gr.ebs.gss.client.exceptions.RpcException;
23 import gr.ebs.gss.server.domain.WebDavNonce;
24 import gr.ebs.gss.server.ejb.ExternalAPI;
26 import java.util.Date;
28 import java.util.UUID;
29 import java.util.concurrent.ConcurrentHashMap;
31 import javax.naming.Context;
32 import javax.naming.InitialContext;
33 import javax.naming.NamingException;
34 import javax.rmi.PortableRemoteObject;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.bradmcevoy.http.Request;
40 import com.bradmcevoy.http.Resource;
41 import com.bradmcevoy.http.http11.auth.ExpiredNonceRemover;
42 import com.bradmcevoy.http.http11.auth.Nonce;
43 import com.bradmcevoy.http.http11.auth.NonceProvider;
44 import com.bradmcevoy.http.http11.auth.SimpleMemoryNonceProvider;
45 import com.bradmcevoy.http.http11.auth.NonceProvider.NonceValidity;
52 public class GssNonceProvider implements NonceProvider {
54 private static final Logger log = LoggerFactory.getLogger( GssNonceProvider.class );
55 private final int nonceValiditySeconds;
56 private boolean enableNonceCountChecking;
57 public GssNonceProvider( int nonceValiditySeconds ) {
58 this.nonceValiditySeconds = nonceValiditySeconds;
62 public String createNonce(Resource resource, Request request ) {
63 UUID id = UUID.randomUUID();
64 Date now = new Date();
65 Nonce n = new Nonce( id, now );
66 createOrUpdateGssNonce(n);
67 return n.getValue().toString();
71 public NonceValidity getNonceValidity( String nonce, Long nc ) {
72 log.trace( "getNonceValidity: " + nonce );
75 value = UUID.fromString( nonce );
76 } catch( Exception e ) {
77 log.warn( "couldnt parse nonce" );
78 return NonceValidity.INVALID;
80 Nonce n = getNonce( nonce );
82 log.debug( "not found");
83 return NonceValidity.INVALID;
85 if( isExpired( n.getIssued() ) ) {
86 log.debug( "nonce has expired" );
87 return NonceValidity.EXPIRED;
90 log.trace( "nonce ok" );
91 return NonceValidity.OK;
93 if( enableNonceCountChecking && nc <= n.getNonceCount() ) {
94 log.warn( "nonce-count was not greater then previous, possible replay attack. new: " + nc + " old:" + n.getNonceCount() );
95 return NonceValidity.INVALID;
97 log.trace( "nonce and nonce-count ok" );
98 Nonce newNonce = n.increaseNonceCount( nc );
99 createOrUpdateGssNonce(newNonce);
100 return NonceValidity.OK;
107 private boolean isExpired( Date issued ) {
108 long dif = ( System.currentTimeMillis() - issued.getTime() ) / 1000;
109 return dif > nonceValiditySeconds;
112 private void createOrUpdateGssNonce(Nonce nonce){
114 WebDavNonce non = getService().getWebDavNonce(nonce.getValue().toString());
116 non = new WebDavNonce();
117 non.setId(nonce.getValue().toString());
119 non.setIssued(nonce.getIssued());
120 non.setNonceCount(nonce.getNonceCount());
121 getService().saveOrUpdateWebDavNonce(non);
124 throw new RuntimeException("Unable to save or update nonce",ex);
128 private Nonce getNonce(String id){
130 WebDavNonce non = getService().getWebDavNonce(id);
132 Nonce nonce = new Nonce(UUID.fromString(id), non.getIssued());
133 nonce.increaseNonceCount(non.getNonceCount());
138 throw new RuntimeException("Unable to retrieve nonce",ex);
144 * A helper method that retrieves a reference to the ExternalAPI bean and
145 * stores it for future use.
147 * @return an ExternalAPI instance
148 * @throws RpcException in case an error occurs
150 protected ExternalAPI getService() throws RpcException {
152 final Context ctx = new InitialContext();
153 final Object ref = ctx.lookup(getConfiguration().getString("externalApiPath"));
154 return (ExternalAPI) PortableRemoteObject.narrow(ref, ExternalAPI.class);
155 } catch (final NamingException e) {
156 log.error("Unable to retrieve the ExternalAPI EJB", e);
157 throw new RpcException("An error occurred while contacting the naming service");
161 * IE seems to send nc (nonce count) parameters out of order. To correctly
162 * implement checking we need to record which nonces have been sent, and not
163 * assume they will be sent in a monotonically increasing sequence.
165 * The quick fix here is to disable checking of the nc param, since other
166 * common servers seem to do so to.
168 * Note that this will allow replay attacks.
172 public boolean isEnableNonceCountChecking() {
173 return enableNonceCountChecking;
176 public void setEnableNonceCountChecking( boolean enableNonceCountChecking ) {
177 this.enableNonceCountChecking = enableNonceCountChecking;