Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

417 add support to send invoices by webservices to portuguese at #435

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions billy-portugal/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@
<version>0.13.1</version>
</dependency>

<!-- support for webservices generated code -->
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
<version>2.3.3</version>
<exclusions>
<exclusion>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.jws</groupId>
<artifactId>jakarta.jws-api</artifactId>
<version>2.1.0</version>
</dependency>

<!-- JUNIT -->
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down Expand Up @@ -129,6 +147,19 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.6</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>

</dependencies>

<build>
Expand Down Expand Up @@ -252,6 +283,27 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>documents</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlDirectory>${project.basedir}/src/main/resources/</wsdlDirectory>
<wsdlFiles>
<wsdlFile>Fatcorews.wsdl</wsdlFile>
</wsdlFiles>
<packageName>com.premiumminds.billy.portugal.webservices.documents</packageName>
<sourceDestDir>src-generated/main/java</sourceDestDir>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright (C) 2017 Premium Minds.
*
* This file is part of billy portugal (PT Pack).
*
* billy portugal (PT Pack) is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* billy portugal (PT Pack) is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with billy portugal (PT Pack). If not, see <http://www.gnu.org/licenses/>.
*/
package com.premiumminds.billy.portugal.services.export.webservice;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Calendar;
import java.util.Set;
import java.util.TimeZone;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

class AuthenticationHandler implements SOAPHandler<SOAPMessageContext> {

private static final String AUTH_NS = "http://schemas.xmlsoap.org/ws/2002/12/secext";
private static final String AUTH_PREFIX = "wss";
private static final SimpleDateFormat TIMESTAMP_FORMATER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'");
static {
TIMESTAMP_FORMATER.setTimeZone(TimeZone.getTimeZone("UTC"));
}

private final WebserviceCredentials webserviceCredentials;
private final WebserviceKeys webserviceKeys;

public AuthenticationHandler(WebserviceCredentials webserviceCredentials, WebserviceKeys webserviceKeys) {
this.webserviceCredentials = webserviceCredentials;
this.webserviceKeys = webserviceKeys;
}

@Override
public Set<QName> getHeaders() {
return null;
}

@Override
public boolean handleMessage(final SOAPMessageContext smc) {
boolean direction = (Boolean) smc.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);

if (direction){
try {
final byte[] simetricKey = generateRequestKey();

final byte[] encryptedPassword = cypherCredential(simetricKey, webserviceCredentials.getPassword());
final String b64EncryptedPassword = Base64.getEncoder().encodeToString(encryptedPassword);

final String timestamp = getTimestamp();
final byte[] encryptedTimestamp = cypherCredential(simetricKey, timestamp);
final String b64EncryptedTimestamp = Base64.getEncoder().encodeToString(encryptedTimestamp);

final Key publicKey = getPublicKeyFromKeystore();
final byte[] encriptedSimetricKey = cypherRequestKey((PublicKey) publicKey, simetricKey);
final String b64EncryptedSimetricKey = Base64.getEncoder().encodeToString(encriptedSimetricKey);

createSoapSecurityHeader(smc, b64EncryptedPassword, b64EncryptedTimestamp, b64EncryptedSimetricKey,
webserviceCredentials.getUsername());

} catch (Exception e){
e.printStackTrace();
return false;
}
}
return true;
}

@Override
public boolean handleFault(final SOAPMessageContext context) {
return false;
}

@Override
public void close(final MessageContext context) {

}

private void createSoapSecurityHeader(SOAPMessageContext smc, String b64EncryptedPassword,
String b64EncryptedTimestamp, String b64EncryptedSimetricKey, String username) throws SOAPException {
SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
SOAPFactory soapFactory = SOAPFactory.newInstance();

SOAPElement wsSecHeaderElm = soapFactory.createElement("Security", AUTH_PREFIX, AUTH_NS);
SOAPElement userNameTokenElm = soapFactory.createElement("UsernameToken", AUTH_PREFIX, AUTH_NS);
SOAPElement userNameElm = soapFactory.createElement("Username", AUTH_PREFIX, AUTH_NS);
userNameElm.addTextNode(username);
SOAPElement passwdElm = soapFactory.createElement("Password", AUTH_PREFIX, AUTH_NS);
passwdElm.addTextNode(b64EncryptedPassword);
SOAPElement nonceElm = soapFactory.createElement("Nonce", AUTH_PREFIX, AUTH_NS);
nonceElm.addTextNode(b64EncryptedSimetricKey);
SOAPElement createdElm = soapFactory.createElement("Created", AUTH_PREFIX, AUTH_NS);
createdElm.addTextNode(b64EncryptedTimestamp);

userNameTokenElm.addChildElement(userNameElm);
userNameTokenElm.addChildElement(passwdElm);
userNameTokenElm.addChildElement(nonceElm);
userNameTokenElm.addChildElement(createdElm);

wsSecHeaderElm.addChildElement(userNameTokenElm);

final SOAPHeader sh = envelope.getHeader();

sh.addChildElement(wsSecHeaderElm);
}

private byte[] cypherRequestKey(PublicKey publicKey, byte[] requestKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(requestKey);
}

public byte[] generateRequestKey() throws NoSuchAlgorithmException {
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);

Key keyToBeWrapped = generator.generateKey();

return keyToBeWrapped.getEncoded();
}

private byte[] cypherCredential(byte[] requestKey, String credential)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(requestKey, "AES"));

return cipher.doFinal(credential.getBytes(StandardCharsets.UTF_8));
}

private Key getPublicKeyFromKeystore()
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {

KeyStore ks = KeyStore.getInstance("JKS");

try (InputStream fis = webserviceKeys.getKeystore().toURL().openStream()) {
ks.load(fis, webserviceKeys.getKeystorePassword().toCharArray());
return ks.getCertificate(webserviceKeys.getKeyAlias()).getPublicKey();
}
}

private static String getTimestamp() {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
return TIMESTAMP_FORMATER.format(c.getTime());
}
}
Loading