Statistics
| Branch: | Tag: | Revision:

root / src / org / gss_project / gss / server / webdav / milton / GssNonceProvider.java @ 1206:292dec4eae08

History | View | Annotate | Download (5.9 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 org.gss_project.gss.server.webdav.milton;
20

    
21
import static org.gss_project.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22
import org.gss_project.gss.common.exceptions.RpcException;
23
import org.gss_project.gss.server.domain.WebDavNonce;
24
import org.gss_project.gss.server.ejb.ExternalAPI;
25

    
26
import java.util.Date;
27
import java.util.UUID;
28

    
29
import javax.naming.Context;
30
import javax.naming.InitialContext;
31
import javax.naming.NamingException;
32
import javax.rmi.PortableRemoteObject;
33

    
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

    
37
import com.bradmcevoy.http.Request;
38
import com.bradmcevoy.http.Resource;
39
import com.bradmcevoy.http.http11.auth.Nonce;
40
import com.bradmcevoy.http.http11.auth.NonceProvider;
41

    
42
/**
43
 * @author kman
44
 *
45
 */
46
public class GssNonceProvider implements NonceProvider {
47

    
48
    private static final Logger log = LoggerFactory.getLogger( GssNonceProvider.class );
49
    private final int nonceValiditySeconds;
50
    private boolean enableNonceCountChecking;
51
    public GssNonceProvider( int nonceValiditySeconds ) {
52
        this.nonceValiditySeconds = nonceValiditySeconds;
53
    }
54
    
55
        @Override
56
        public String createNonce(Resource resource, Request request ) {
57
                UUID id = UUID.randomUUID();
58
        Date now = new Date();
59
        Nonce n = new Nonce( id, now );
60
        createOrUpdateGssNonce(n);
61
        return n.getValue().toString();
62
        }
63

    
64
        @Override
65
        public NonceValidity getNonceValidity( String nonce, Long nc ) {
66
        log.trace( "getNonceValidity: " + nonce );
67
        UUID value = null;
68
        try {
69
            value = UUID.fromString( nonce );
70
        } catch( Exception e ) {
71
            log.warn( "couldnt parse nonce" );
72
            return NonceValidity.INVALID;
73
        }
74
        Nonce n = getNonce( nonce );
75
        if( n == null ) {
76
            log.debug( "not found");
77
            return NonceValidity.INVALID;
78
        } else {
79
            if( isExpired( n.getIssued() ) ) {
80
                log.debug( "nonce has expired" );
81
                return NonceValidity.EXPIRED;
82
            } else {
83
                if( nc == null ) {
84
                    log.trace( "nonce ok" );
85
                    return NonceValidity.OK;
86
                } else {
87
                    if( enableNonceCountChecking && nc <= n.getNonceCount() ) {
88
                        log.warn( "nonce-count was not greater then previous, possible replay attack. new: " + nc + " old:" + n.getNonceCount() );
89
                        return NonceValidity.INVALID;
90
                    } else {
91
                        log.trace( "nonce and nonce-count ok" );
92
                        Nonce newNonce = n.increaseNonceCount( nc );
93
                        createOrUpdateGssNonce(newNonce);
94
                        return NonceValidity.OK;
95
                    }
96
                }
97
            }
98
        }
99
    }
100

    
101
    private boolean isExpired( Date issued ) {
102
        long dif = ( System.currentTimeMillis() - issued.getTime() ) / 1000;
103
        return dif > nonceValiditySeconds;
104
    }
105
    
106
    private void createOrUpdateGssNonce(Nonce nonce){
107
            try{
108
                    WebDavNonce non = getService().getWebDavNonce(nonce.getValue().toString());
109
                    if(non==null){
110
                            non = new WebDavNonce();
111
                            non.setId(nonce.getValue().toString());
112
                    }
113
                    non.setIssued(nonce.getIssued());
114
                    non.setNonceCount(nonce.getNonceCount());
115
                    getService().saveOrUpdateWebDavNonce(non);
116
            }
117
            catch(Exception ex){
118
                    throw new RuntimeException("Unable to save or update nonce",ex);
119
            }
120
    }
121
    
122
    private Nonce getNonce(String id){
123
            try{
124
                    WebDavNonce non = getService().getWebDavNonce(id);
125
                    if(non!=null){
126
                            Nonce nonce = new Nonce(UUID.fromString(id), non.getIssued());
127
                            nonce.increaseNonceCount(non.getNonceCount());
128
                            return nonce;
129
                    }
130
            }
131
            catch(Exception ex){
132
                    throw new RuntimeException("Unable to retrieve nonce",ex);
133
            }
134
            return null;
135
    }
136
    
137
    /**
138
         * A helper method that retrieves a reference to the ExternalAPI bean and
139
         * stores it for future use.
140
         *
141
         * @return an ExternalAPI instance
142
         * @throws RpcException in case an error occurs
143
         */
144
        protected ExternalAPI getService() throws RpcException {
145
                try {
146
                        final Context ctx = new InitialContext();
147
                        final Object ref = ctx.lookup(getConfiguration().getString("externalApiPath"));
148
                        return (ExternalAPI) PortableRemoteObject.narrow(ref, ExternalAPI.class);
149
                } catch (final NamingException e) {
150
                        log.error("Unable to retrieve the ExternalAPI EJB", e);
151
                        throw new RpcException("An error occurred while contacting the naming service");
152
                }
153
        }
154
        /**
155
     * IE seems to send nc (nonce count) parameters out of order. To correctly
156
     * implement checking we need to record which nonces have been sent, and not
157
     * assume they will be sent in a monotonically increasing sequence.
158
     *
159
     * The quick fix here is to disable checking of the nc param, since other
160
     * common servers seem to do so to.
161
     *
162
     * Note that this will allow replay attacks.
163
     *
164
     * @return
165
     */
166
    public boolean isEnableNonceCountChecking() {
167
        return enableNonceCountChecking;
168
    }
169

    
170
   public void setEnableNonceCountChecking( boolean enableNonceCountChecking ) {
171
       this.enableNonceCountChecking = enableNonceCountChecking;
172
   }
173
}