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        try
062        {
063            InputStream is =
064                Thread.currentThread().getContextClassLoader().getResourceAsStream( "ssh-keys/id_rsa.pub" );
065            PublicKey publicKey = decodePublicKey( IOUtil.toString( is ) );
066            publickeyAuthenticatorRequests.add( new PublickeyAuthenticatorRequest( username, key ) );
067
068            return ( (RSAPublicKey) publicKey ).getModulus().equals( ( (RSAPublicKey) publicKey ).getModulus() );
069        }
070        catch ( Exception e )
071        {
072            throw new RuntimeException( e.getMessage(), e );
073        }
074    }
075
076    public static byte[] decrypt( byte[] text, PrivateKey key )
077        throws Exception
078    {
079        byte[] dectyptedText = null;
080        Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
081        cipher.init( Cipher.DECRYPT_MODE, key );
082        dectyptedText = cipher.doFinal( text );
083        return dectyptedText;
084    }
085
086    /**
087     * 
088     */
089    public static class PublickeyAuthenticatorRequest
090    {
091        private String username;
092
093        private PublicKey publicKey;
094
095        public PublickeyAuthenticatorRequest( String username, PublicKey publicKey )
096        {
097            this.username = username;
098            this.publicKey = publicKey;
099        }
100
101        @Override
102        public String toString()
103        {
104            final StringBuilder sb = new StringBuilder();
105            sb.append( "PublickeyAuthenticatorRequest" );
106            sb.append( "{username='" ).append( username ).append( '\'' );
107            sb.append( ", publicKey=" ).append( publicKey );
108            sb.append( '}' );
109            return sb.toString();
110        }
111    }
112
113    private byte[] bytes;
114
115    private int pos;
116
117    public PublicKey decodePublicKey( String keyLine )
118        throws Exception
119    {
120        bytes = null;
121        pos = 0;
122
123        for ( String part : keyLine.split( " " ) )
124        {
125            if ( part.startsWith( "AAAA" ) )
126            {
127                bytes = Base64.decodeBase64( part.getBytes() );
128                break;
129            }
130        }
131        if ( bytes == null )
132        {
133            throw new IllegalArgumentException( "no Base64 part to decode" );
134        }
135
136        String type = decodeType();
137        if ( type.equals( "ssh-rsa" ) )
138        {
139            BigInteger e = decodeBigInt();
140            BigInteger m = decodeBigInt();
141            RSAPublicKeySpec spec = new RSAPublicKeySpec( m, e );
142            return KeyFactory.getInstance( "RSA" ).generatePublic( spec );
143        }
144        else if ( type.equals( "ssh-dss" ) )
145        {
146            BigInteger p = decodeBigInt();
147            BigInteger q = decodeBigInt();
148            BigInteger g = decodeBigInt();
149            BigInteger y = decodeBigInt();
150            DSAPublicKeySpec spec = new DSAPublicKeySpec( y, p, q, g );
151            return KeyFactory.getInstance( "DSA" ).generatePublic( spec );
152        }
153        else
154        {
155            throw new IllegalArgumentException( "unknown type " + type );
156        }
157    }
158
159    private String decodeType()
160    {
161        int len = decodeInt();
162        String type = new String( bytes, pos, len );
163        pos += len;
164        return type;
165    }
166
167    private int decodeInt()
168    {
169        // CHECKSTYLE_OFF: MagicNumber
170        return ( ( bytes[pos++] & 0xFF ) << 24 ) | ( ( bytes[pos++] & 0xFF ) << 16 ) | ( ( bytes[pos++] & 0xFF ) << 8 )
171            | ( bytes[pos++] & 0xFF );
172        // CHECKSTYLE_ON: MagicNumber
173    }
174
175    private BigInteger decodeBigInt()
176    {
177        int len = decodeInt();
178        byte[] bigIntBytes = new byte[len];
179        System.arraycopy( bytes, pos, bigIntBytes, 0, len );
180        pos += len;
181        return new BigInteger( bigIntBytes );
182    }
183
184}