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