Statistics
| Branch: | Tag: | Revision:

root / src / gr / ebs / gss / server / webdav / milton / GssNonceProvider.java @ 065ce8c1

History | View | Annotate | Download (6 kB)

1
/*
2
 * Copyright 2011 Electronic Business Systems Ltd.
3
 *
4
 * This file is part of GSS.
5
 *
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.
10
 *
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.
15
 *
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/>.
18
 */
19
package gr.ebs.gss.server.webdav.milton;
20

    
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;
25

    
26
import java.util.Date;
27
import java.util.Map;
28
import java.util.UUID;
29
import java.util.concurrent.ConcurrentHashMap;
30

    
31
import javax.naming.Context;
32
import javax.naming.InitialContext;
33
import javax.naming.NamingException;
34
import javax.rmi.PortableRemoteObject;
35

    
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38

    
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;
46

    
47

    
48
/**
49
 * @author kman
50
 *
51
 */
52
public class GssNonceProvider implements NonceProvider {
53

    
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;
59
    }
60
    
61
        @Override
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();
68
        }
69

    
70
        @Override
71
        public NonceValidity getNonceValidity( String nonce, Long nc ) {
72
        log.trace( "getNonceValidity: " + nonce );
73
        UUID value = null;
74
        try {
75
            value = UUID.fromString( nonce );
76
        } catch( Exception e ) {
77
            log.warn( "couldnt parse nonce" );
78
            return NonceValidity.INVALID;
79
        }
80
        Nonce n = getNonce( nonce );
81
        if( n == null ) {
82
            log.debug( "not found");
83
            return NonceValidity.INVALID;
84
        } else {
85
            if( isExpired( n.getIssued() ) ) {
86
                log.debug( "nonce has expired" );
87
                return NonceValidity.EXPIRED;
88
            } else {
89
                if( nc == null ) {
90
                    log.trace( "nonce ok" );
91
                    return NonceValidity.OK;
92
                } else {
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;
96
                    } else {
97
                        log.trace( "nonce and nonce-count ok" );
98
                        Nonce newNonce = n.increaseNonceCount( nc );
99
                        createOrUpdateGssNonce(newNonce);
100
                        return NonceValidity.OK;
101
                    }
102
                }
103
            }
104
        }
105
    }
106

    
107
    private boolean isExpired( Date issued ) {
108
        long dif = ( System.currentTimeMillis() - issued.getTime() ) / 1000;
109
        return dif > nonceValiditySeconds;
110
    }
111
    
112
    private void createOrUpdateGssNonce(Nonce nonce){
113
            try{
114
                    WebDavNonce non = getService().getWebDavNonce(nonce.getValue().toString());
115
                    if(non==null){
116
                            non = new WebDavNonce();
117
                            non.setId(nonce.getValue().toString());
118
                    }
119
                    non.setIssued(nonce.getIssued());
120
                    non.setNonceCount(nonce.getNonceCount());
121
                    getService().saveOrUpdateWebDavNonce(non);
122
            }
123
            catch(Exception ex){
124
                    ex.printStackTrace();
125
            }
126
    }
127
    
128
    private Nonce getNonce(String id){
129
            try{
130
                    WebDavNonce non = getService().getWebDavNonce(id);
131
                    if(non!=null){
132
                            Nonce nonce = new Nonce(UUID.fromString(id), non.getIssued());
133
                            nonce.increaseNonceCount(non.getNonceCount());
134
                            return nonce;
135
                    }
136
            }
137
            catch(Exception ex){
138
                    ex.printStackTrace();
139
            }
140
            return null;
141
    }
142
    
143
    /**
144
         * A helper method that retrieves a reference to the ExternalAPI bean and
145
         * stores it for future use.
146
         *
147
         * @return an ExternalAPI instance
148
         * @throws RpcException in case an error occurs
149
         */
150
        protected ExternalAPI getService() throws RpcException {
151
                try {
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");
158
                }
159
        }
160
        /**
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.
164
     *
165
     * The quick fix here is to disable checking of the nc param, since other
166
     * common servers seem to do so to.
167
     *
168
     * Note that this will allow replay attacks.
169
     *
170
     * @return
171
     */
172
    public boolean isEnableNonceCountChecking() {
173
        return enableNonceCountChecking;
174
    }
175

    
176
   public void setEnableNonceCountChecking( boolean enableNonceCountChecking ) {
177
       this.enableNonceCountChecking = enableNonceCountChecking;
178
   }
179
}