001package org.apache.maven.wagon.providers.ssh;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.mina.util.Base64;
023import org.apache.sshd.server.PublickeyAuthenticator;
024import org.apache.sshd.server.session.ServerSession;
025import org.codehaus.plexus.util.IOUtil;
026
027import javax.crypto.Cipher;
028import java.io.InputStream;
029import java.math.BigInteger;
030import java.security.KeyFactory;
031import java.security.PrivateKey;
032import java.security.PublicKey;
033import java.security.interfaces.RSAPublicKey;
034import java.security.spec.DSAPublicKeySpec;
035import java.security.spec.RSAPublicKeySpec;
036import java.util.ArrayList;
037import java.util.List;
038
039/**
040 * @author Olivier Lamy
041 */
042public class TestPublickeyAuthenticator
043    implements PublickeyAuthenticator
044{
045    private List<PublickeyAuthenticatorRequest> publickeyAuthenticatorRequests =
046        new ArrayList<PublickeyAuthenticatorRequest>();
047
048    private boolean keyAuthz;
049
050    public TestPublickeyAuthenticator( boolean keyAuthz )
051    {
052        this.keyAuthz = keyAuthz;
053    }
054
055    public boolean authenticate( String username, PublicKey key, ServerSession session )
056    {
057        if ( !keyAuthz )
058        {
059            return false;
060        }
061        InputStream in = null;
062        try
063        {
064            in = Thread.currentThread().getContextClassLoader().getResourceAsStream( "ssh-keys/id_rsa.pub" );
065            PublicKey publicKey = decodePublicKey( IOUtil.toString( in ) );
066            in.close();
067            in = null;
068
069            publickeyAuthenticatorRequests.add( new PublickeyAuthenticatorRequest( username, key ) );
070
071            return ( (RSAPublicKey) publicKey ).getModulus().equals( ( (RSAPublicKey) publicKey ).getModulus() );
072        }
073        catch ( Exception e )
074        {
075            throw new RuntimeException( e.getMessage(), e );
076        }
077        finally
078        {
079            IOUtil.close( in );
080        }
081    }
082
083    public static byte[] decrypt( byte[] text, PrivateKey key )
084        throws Exception
085    {
086        byte[] dectyptedText = null;
087        Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
088        cipher.init( Cipher.DECRYPT_MODE, key );
089        dectyptedText = cipher.doFinal( text );
090        return dectyptedText;
091    }
092
093    /**
094     * 
095     */
096    public static class PublickeyAuthenticatorRequest
097    {
098        private String username;
099
100        private PublicKey publicKey;
101
102        public PublickeyAuthenticatorRequest( String username, PublicKey publicKey )
103        {
104            this.username = username;
105            this.publicKey = publicKey;
106        }
107
108        @Override
109        public String toString()
110        {
111            final StringBuilder sb = new StringBuilder();
112            sb.append( "PublickeyAuthenticatorRequest" );
113            sb.append( "{username='" ).append( username ).append( '\'' );
114            sb.append( ", publicKey=" ).append( publicKey );
115            sb.append( '}' );
116            return sb.toString();
117        }
118    }
119
120    private byte[] bytes;
121
122    private int pos;
123
124    public PublicKey decodePublicKey( String keyLine )
125        throws Exception
126    {
127        bytes = null;
128        pos = 0;
129
130        for ( String part : keyLine.split( " " ) )
131        {
132            if ( part.startsWith( "AAAA" ) )
133            {
134                bytes = Base64.decodeBase64( part.getBytes() );
135                break;
136            }
137        }
138        if ( bytes == null )
139        {
140            throw new IllegalArgumentException( "no Base64 part to decode" );
141        }
142
143        String type = decodeType();
144        if ( type.equals( "ssh-rsa" ) )
145        {
146            BigInteger e = decodeBigInt();
147            BigInteger m = decodeBigInt();
148            RSAPublicKeySpec spec = new RSAPublicKeySpec( m, e );
149            return KeyFactory.getInstance( "RSA" ).generatePublic( spec );
150        }
151        else if ( type.equals( "ssh-dss" ) )
152        {
153            BigInteger p = decodeBigInt();
154            BigInteger q = decodeBigInt();
155            BigInteger g = decodeBigInt();
156            BigInteger y = decodeBigInt();
157            DSAPublicKeySpec spec = new DSAPublicKeySpec( y, p, q, g );
158            return KeyFactory.getInstance( "DSA" ).generatePublic( spec );
159        }
160        else
161        {
162            throw new IllegalArgumentException( "unknown type " + type );
163        }
164    }
165
166    private String decodeType()
167    {
168        int len = decodeInt();
169        String type = new String( bytes, pos, len );
170        pos += len;
171        return type;
172    }
173
174    private int decodeInt()
175    {
176        // CHECKSTYLE_OFF: MagicNumber
177        return ( ( bytes[pos++] & 0xFF ) << 24 ) | ( ( bytes[pos++] & 0xFF ) << 16 ) | ( ( bytes[pos++] & 0xFF ) << 8 )
178            | ( bytes[pos++] & 0xFF );
179        // CHECKSTYLE_ON: MagicNumber
180    }
181
182    private BigInteger decodeBigInt()
183    {
184        int len = decodeInt();
185        byte[] bigIntBytes = new byte[len];
186        System.arraycopy( bytes, pos, bigIntBytes, 0, len );
187        pos += len;
188        return new BigInteger( bigIntBytes );
189    }
190
191}