Java applet java.security.AccessControlException - java

I'm working on an Java applet that prints a file.
The applet is "self-signed".
The print function is:
//argFilePath : path to file (http://localhost/Teste/pdf1.pdf)
//argPrintService : something like PrintServiceLookup.lookupDefaultPrintService()
private int print(String argFilePath, PrintService argPrintService){
try
{
DocPrintJob printJob = argPrintService.createPrintJob();
Doc doc;
DocAttributeSet docAttrSet = new HashDocAttributeSet();
PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
URL url = new URL(argFilePath);
doc = new SimpleDoc(url.openStream(), DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
printJob.print(doc, printReqAttr);
} catch (Exception e) {
System.out.println(e);
return 1;
}
return 0;
}
I get this exception when trying to open the file:
java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:80 connect,resolve)
HTML/JavaScrip
<input onclick="alert(document.getElementById('xpto').print('http://localhost/Teste/pdf1.pdf'));" type="button"/>
<applet width="180" height="120" code="printers.class" id="xpto" archive="printerAPI.jar"></applet>
is correct to use:
DocFlavor.INPUT_STREAM.AUTOSENSE
The idea seems to be to print as many file type as possible - pdf, docx, jpg, etc.
How can you fix the exception?

Found the answer (on stackoverflow lol :D)!
It looks like the problem was:
"javascript does not have file access permissions"
so the applet is blocked. we have to use
AccessController.doPrivileged()
doPrivileged
Here is my implementation:
private int print(String argFilePath, PrintService argPrintService){
cPrint cP = new cPrint(argFilePath, argPrintService);
return (Integer) AccessController.doPrivileged(cP);
}
class cPrint implements PrivilegedAction<Object> {
String FilePath;
PrintService PrintService;
public cPrint(String argFilePath, PrintService argPrintService) {
this.FilePath = argFilePath;
this.PrintService = argPrintService;
};
public Object run() {
// privileged code goes here
try
{
DocPrintJob printJob = PrintService.createPrintJob();
Doc doc;
DocAttributeSet docAttrSet = new HashDocAttributeSet();
PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
URL url = new URL(FilePath);
doc = new SimpleDoc(url.openStream(), DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
printJob.print(doc, printReqAttr);
} catch (Exception e) {
System.out.println(e);
return 1;
}
return 0;
}
}

You probably got this:
java.security.AccessControlException: access denied (java.net.SocketPermission
127.0.0.1:80 connect,resolve)
because applets can't make connections to websites, other than the one they came from. Now, this is terribly silly because one would think localhost is not another website, but the Java SecurityManager must only look at IP address. Therefore, if the browser is connected to 74.125.224.224 then the Java applet must connect to that address—which is different from localhost, whose address is 127.0.0.1.
This will just take care of the Socket Permission error. But, you'll probably run into something else if you're trying to access the user's hardware. In which case, you'll need to make a certificate and the user will choose whether or not to run your applet.
If you just want to run this on your home computer then, you need a plain-text java.policy file in your home directory. (~/.java.policy for Unix people.) In that file you'll type:
grant{
permission java.security.AllPermission;
};
After you save this file in your home directory, all java applets will be given full permission to run—anything. It'll be like the SecurityManager doesn't exist, so try to be a bit careful. After you're done with testing, I'd recommend to delete this file.

Related

Java - CopyStreamException due to SSLProtocolException when storing file's contents in FTP server

I'm facing an issue when trying to store a file in an FTP server. When trying to upload a file to the FTP server, the file is created but its contents are not copied.
Context
We use the following configuration to access the FTP server using lftp. I cannot change this configuration, and don't know why do we use FTPS with verify-certificates disabled.
# FTPS_OPTIONS:
set ssl:verify-certificate/testhostname no;
set ftp:ssl-protect-data yes;
set ftp:passive-mode on;
I need to store certain files from a Java application. I'm using apache-commons library. The implemented code looks like this:
#Autowired
public FtpService() {
ftpsClient = new FTPSClient();
ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
}
public void uploadFile(String ftpHost, File tempFile, String destination, String filename)
throws UploadException {
ftpsClient.connect(ftpHost, 990);
ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
ftpsClient.enterLocalPassiveMode();
ftpsClient.setKeepAlive(true);
ftpsClient.setControlKeepAliveTimeout(3000);
if(ftpsClient.login("user", "password")) {
try (InputStream fileStream = new FileInputStream(tempFile)) {
if (!ftpsClient.changeWorkingDirectory(destination)) {
throwUploadException("Destination directory not available in FTP server");
}
boolean saved = ftpsClient.storeFile(filename, fileStream);
// Following code is not executed since the exception is thrown in the previous line
if (!saved) {
throwUploadException("Unable to save file in FTP server");
}
log.info("Saved FTP file: {}/{}", destination, filename);
}
catch (UploadException | IOException e)
{
throwUploadException(e.getMessage());
}
finally
{
ftpsClient.disconnect();
if (!tempFile.delete()) {
log.warn("Unable to delete '{}' file", tempFile.getAbsolutePath());
}
}
}
}
Problem
I started with a FTPClient (non FTPSClient) but this way I wasn't able to login.
Currently (FTPSClient), I can:
change the working directory
create directories in the FTP server
I cannot:
storeFile: this method throws the following exception, and creates the file in the FTP server, but this is empty
org.apache.commons.net.io.CopyStreamException: IOException caught while copying.
Cause: javax.net.ssl.SSLProtocolException: Software caused connection abort: socket write error
listFiles()/listDirectories(): when executing this command, the obtained list is always empty. The logged user has all the required permissions in the whole FTP server
Following is the FTP's log (note that I have translated the commands to English between parenthesis), corresponding to the code shown before, that raises the exception mentioned before:
er: testhostname:990
USER *******
331 Usuario testuser OK. Clave requerida ( = User testuser OK. Password required)
PASS *******
230 OK. El directorio restringido actual es / ( = OK. The current restricted directory is /)
CWD /test/upload
250 OK. El directorio actual es /test/upload ( = Ok. The current directory is /test/upload)
PASV
227 Entering Passive Mode (<numbers...>)
[Replacing PASV mode reply address <ip_address> with testhostname]
STOR dummyfile.txt
150 Conexi├│n de datos aceptada ( = Data connection accepted)
If there is anything else I can include to improve the description, please let me know. Thanks for your help!
I had a similar problem from python connecting to an FTPS server. The error was that the server required the data channel session to be the same as the control channel session(reuse the session). The solution was to override one of the methods to do that.
You can test extending FTPClient.java and overriding the next method:
#Override
protected void _prepareDataSocket_(final Socket socket) {
if(preferences.getBoolean("ftp.tls.session.requirereuse")) {
if(socket instanceof SSLSocket) {
// Control socket is SSL
final SSLSession session = ((SSLSocket) _socket_).getSession();
if(session.isValid()) {
final SSLSessionContext context = session.getSessionContext();
context.setSessionCacheSize(preferences.getInteger("ftp.ssl.session.cache.size"));
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
Method getHostMethod;
try {
getHostMethod = socket.getClass().getMethod("getPeerHost");
}
catch(NoSuchMethodException e) {
// Running in IKVM
getHostMethod = socket.getClass().getDeclaredMethod("getHost");
}
getHostMethod.setAccessible(true);
Object peerHost = getHostMethod.invoke(socket);
putMethod.invoke(cache, String.format("%s:%s", peerHost, socket.getPort()).toLowerCase(Locale.ROOT), session);
}
catch(NoSuchFieldException e) {
// Not running in expected JRE
log.warn("No field sessionHostPortCache in SSLSessionContext", e);
}
catch(Exception e) {
// Not running in expected JRE
log.warn(e.getMessage());
}
}
else {
log.warn(String.format("SSL session %s for socket %s is not rejoinable", session, socket));
}
}
}
}
I found this Java solution here: https://stackoverflow.com/a/32404418/19599290

Using a security manager with reflection accessing a jar file

After implementing my platform to have the ability to load jar files dynamically using reflection, I come across a security issue. The jar file could be 'dangerous' and contain code that could effect things, therefore I come across on SO the use of using a SecurityManager.
I am loading the jar file like this (example of hard coded file):
URLClassLoader clsLoader = URLClassLoader
.newInstance(new URL[] { new URL("file:/C://Temp/SettingsApp.jar") });
Class<?> cls = clsLoader.loadClass("iezon.app.SettingsApp");
JPanel settingsApp = (JPanel) cls.newInstance();
I have tried to use the SecurityManager like so:
try {
SecurityManager sm = new SecurityManager();
Object context = sm.getSecurityContext();
sm.checkPermission(new AllPermission(), context);
settingsAppPanel = (JPanel) cls.newInstance();
} catch (AccessControlException e) {
e.printStackTrace();
}
The test with AllPermission() works and gives me this exception:
java.security.AccessControlException: access denied ("java.security.AllPermission" "" "")
However, I am unable to find any information on how to bind the jar file to this security manager and not the current platform. I just don't want the jar file to be able to open sockets, etc.. without firstly requesting permissions that the user can then accept.
I stumbled across BasicPermission, however, this is an abstract class and cannot be instanced like the AllPermission and likewise, I am unable to find any information on approaching this. Any help would be appreciated!
As #Holger mentioned in the comments, the only way to implement using a Security Manager is to dynamically create policies. Therefore, when a developer uploads a new app to the appstore, he is given a set of policies to declare that his app uses. On the app, this is then fed to the user asking them to confirm this policy (at their own risk if it involves sockets etc...) and then a policy is created and the app can run:
if (!app.policyIsAgreedTo()) {
if(readPolicy(app).get(0).equalsIgnoreCase("grant {")) {
app.setPolicy(true);
} else {
throw new Exception("App policy has not been agreed to.");
}
}
if (app.policyIsAgreedTo()) {
System.setProperty("java.security.policy", "file:/C:/Temp/" + app.getName() + ".policy");
System.setSecurityManager(new SecurityManager());
JPanel panel = (JPanel) app.getObject().newInstance();
System.setSecurityManager(null);
return panel;
}
throw new Exception("App policy has not been agreed to.");
The policy gets created like so:
public static void createPolicy(ArrayList<String> policies, App app) {
try {
FileWriter fileWriter =
new FileWriter("C:/Temp/" + app.getName() + ".policy");
BufferedWriter bufferedWriter =
new BufferedWriter(fileWriter);
bufferedWriter.write("grant {");
bufferedWriter.newLine();
for(String policy : policies) {
bufferedWriter.write(" permission java.lang.RuntimePermission \"" + policy + "\";");
bufferedWriter.newLine();
}
bufferedWriter.write("};");
bufferedWriter.close();
} catch(IOException ex) {
ex.printStackTrace();
}
}
The app makes an API call to the app store gathering the permissions the app needs, then a simple createPolicy() is called with the permissions in an ArrayList ie:
new ArrayList<String>() {{ add("setSecurityManager"); }}; // Etc...

java code--how to detect if a browser is opened

I would like to know any java method can be used to check if the browser is closed.
I used the following code to open a default browser:
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
desktop.browse(new URI(url));
}
Then I want to perform some user actions on the opened website to capture the web traffic. After the browser is closed the web traffic will be saved.
So how can I determine if the browser is closed by using java code?
The best you can do is use Process builder:
public class Main {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("C:\\Windows\\System32\\calc.exe");
Process p1 = pb.start();
p1.waitFor();
System.out.println(p1.exitValue());
} catch (Exception e) {
System.out.print(e);
}
}
}
You can launch a browser with the webpage as an argument and keep track of it like that.

Tesseract implementing a web service to trigger OCR actions

I am trying to implement a web service which triggers OCR actions of the server side.
Client code:
...
sy = belgeArsivle(testServisIstegi, ab);
...
private static ServisYaniti belgeArsivle(com.ocr.ws.ServiceRequest serviceRequest,com.ocr.ws.Document document) {
com.ocr.ws.ServiceRequest service = new com.ocr.ws.OCRArsivWSService();
com.ocr.ws.OCRArsivWS port = service.getOCRArsivWSPort();
return port.docArchive(serviceRequest, document);
}
When I run the code on the server side there is no problem. But whenever I call the web service method from the client I got this error code:
Exception: javax.xml.ws.soap.SOAPFaultException: Unable to load library 'libtesseract302': The specified module could not be found.
The working server-side code is:
public static void main(String[] args) {
// TODO code application logic here
File imageFile = new File("...OCR\\testTurWithBarcodeScanned.png");
Tesseract instance = Tesseract.getInstance();
try {
String lang = "tur";
instance.setLanguage(lang);
String result = instance.doOCR(imageFile);
System.out.println(result);
// write in a file
try {
File file = new File("...MyOutputWithBarcode.txt");
BufferedWriter out = new BufferedWriter(new FileWriter(file));
out.write(result);
out.close();
} catch (IOException ex) {
}
} catch (TesseractException ep) {
System.err.println(ep.getMessage());
}
}
I know that this error code is about Tesseract libraries. I put the corresponding .dll files (liblept168 and libtesseract302) under the client project's folder, added corresponding libraries (jna, jai_imageio, ghost4j_0.3.1), did neccessary changes in classpath but still getting this error.
I run a test code on the server side, it works fine. But the client side code is not working. Do I need to make some extra adjustment on the client side to run this web service?
I found out that the actual problem was with the Tomcat Server. I had to put the jar files to the Tomcat's Sources under Properties, than voila!

printing to a networked printer using java

i require to send a pdf document to print on the server side of a web app, the printer fully supports pdf printing etc, it is networked as well to the server. The pdf is also stored on the server.
what i am trying to is on a button click, print out the pdf file, currently i have the code below :
//Server side printing
public class PrintDocument {
public void printText(String text) throws PrintException, IOException {
//Looks for all printers
//PrintService[] printServices = PrinterJob.lookupPrintServices();
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
InputStream is = new ByteArrayInputStream(text.getBytes("UTF8"));
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new Copies(1));
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc doc = new SimpleDoc(is, flavor, null);
DocPrintJob job = service.createPrintJob();
PrintJobWatcher pjw = new PrintJobWatcher(job);
job.print(doc, pras);
pjw.waitForDone();
is.close();
}
}
class PrintJobWatcher {
boolean done = false;
PrintJobWatcher(DocPrintJob job) {
job.addPrintJobListener(new PrintJobAdapter() {
public void printJobCanceled(PrintJobEvent pje) {
allDone();
}
public void printJobCompleted(PrintJobEvent pje) {
allDone();
}
public void printJobFailed(PrintJobEvent pje) {
allDone();
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
allDone();
}
void allDone() {
synchronized (PrintJobWatcher.this) {
done = true;
System.out.println("Printing has successfully completed, please collect your prints)");
PrintJobWatcher.this.notify();
}
}
});
}
public synchronized void waitForDone() {
try {
while (!done) {
wait();
}
} catch (InterruptedException e) {
}
}
}
But i have a few questions / issues, how do i put the pdf into the input stream for this to be printed out, can i select options such as duplex printing, and how can i call this from inside a JSF web app
Thanks
According to this article it should be possible to start a print job with a PJL block (Wikipedia link includes pointers to the PJL reference documentation), followed by the PDF data.
Thank to PJL you should be able to control all features the printer has to offer including duplex, etc - the blog article even mentions stapling of a combined printout of 2 pdfs.
Be sure to read the comments on the article as well, there is a comment from the guy who's listed as inventor on the patent as well with extra information on the PJL commands.
Take a look at this blog. We had to print documents with duplex print option.
Its not possible to duplex print directly in java. However the work around is to use ghostscript and convert PDF to PS (Post script file). To that you can add either PJL Commands or Post script commands.
More info at
http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-java-how.html
Also read similar question
Printing with Attributes(Tray Control, Duplex, etc...) using javax.print library
After reading through this Q&A I spent awhile working with the javax.print library only to discover that it is not very consistent with printer option support. I.e. even if a printer has an option like stapling, the javax.printer library showed it as "stapling not supported".
So I then tried out PJL commands using a plain java socket and it worked great, in my tests it also printed faster than the javax.print library, it has a much smaller code footprint and best part is no libraries are needed at all:
private static void print(File document, String printerIpAddress)
{
try (Socket socket = new Socket(printerIpAddress, 9100))
{
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
String title = document.getName();
byte[] bytes = Files.readAllBytes(document.toPath());
out.write(27);
out.write("%-12345X#PJL\n".getBytes());
out.write(("#PJL SET JOBNAME=" + title + "\n").getBytes());
out.write("#PJL SET DUPLEX=ON\n".getBytes());
out.write("#PJL SET STAPLEOPTION=ONE\n".getBytes());
out.write("#PJL ENTER LANGUAGE=PDF\n".getBytes());
out.write(bytes);
out.write(27);
out.write("%-12345X".getBytes());
out.flush();
out.close();
}
catch (Exception e)
{
System.out.println(e);
}
}
See this for more info on attempts with javax.print.

Categories

Resources