I have designed an Applet to take a screenshot and save it on the users computer using the java.awt.Robot class. I need to embedd this applet into an html page (using the object tag) so that when the user clicks a button on the webpage the screenshot is taken.
The applet itself works fine, i've tested it by adding a temporary main method to it and running it on my local machine as a regular java app.
Where I'm having difficulty is setting up permissions to allow it to run from its embedded location. Obviously the robot class is somewhat hazardous so an AWTPermission needs to be established and the applet itself needs to be signed.
I followed through the tutorial at http://download.oracle.com/javase/tutorial/security/toolsign/index.html and succeeded in creating a signed .jar file and then a policy file that allowed the demo application in that tutorial to run. Where I am now running into issues is how to reconcile what I've learned with the situation my applet will be used in.
My target audience comprises around 100 machines and I need it to be executable on all of them. I have packed my java .class file into a .jar and signed it using keytool and jarsigner. I then uploaded the .jar and .cer files to the server directory where the pages in question are hosted.
However: When I then used policytool to create a new policy file on one of the machines to test the setup I am still unable to execute the applet from the HTML. I get Java.Security.AccessControlException Acess Denied java.awt.AWTPermission createRobot errors.
I rather suspect its the policy step that is going awry, so I'll outline the steps I took:
I download the certificate to the local machine and generate a keystore from it, I launch 'policytool' from this directory through the commandline
I add the directory on the local machine where the keystore generated from and my certificate is located.
I then hit the add policy button and enter the SignedBy alias
Then Add Permissions and select AWTPermission
Targets name I select createRobot
The function field I have been leaving blank as I cant think what would apply here
Signed By in this window is also left blank
I then hit 'OK' and 'Done' and get a warning that there is no public key for the alias I've entered in the first step. I do a 'save as' and save my policyfile to the same directory as I put the certificate and the keystore generated from it.
This is not allowing me to run the applet from the webpage however and my limited understanding of this aspect of programming offers no clues as to what has gone wrong.
Ideas, thoughts, observations? If I havent explicitly mentioned something then I havent done it. My biggest suspect is the warning I recieve but I cant seem to find why its appearing
EDIT: Forgot to mention a step. I manually added to my jre\lib\security\java.security file the line 'policy.url.3=file:/C:/Testing/debugpolicy' since thats the path and policy filename I created during the above steps. I also just now managed to remove the warning I mentioned earlier, I'd been mixing up my alias' and gave the alias for the private keystore rather than the public one during policyfile creation, however I still encounter the same problems
If an applet is correctly signed, no policy file is required, nor is it required to separately upload any certificate. A correctly signed applet will prompt the user for permission when the applet is visited, before it loads. Does the prompt appear?
Here is a small demo. I wrote that demonstrates Defensive loading of trusted applets. That is the security prompt I am referring to.
If the applet is both digitally signed by the developer and trusted by the end user, it should be able to take a screen-shot.
There is one other thing you might try if the applet is trusted, just as an experiment (1). Early in the applet init(), call System.setSecurityManager(null). That will both test if the applet has trust, and wipe away the last remnants of the 'trusted' security manager given to applets.
And in the case that works, and it makes the screen capture successful, it suggests either a bug or Oracle changed their mind about the defaults of what a trusted applet could do.
1) Don't do this in a real world or production environment. To quote Tom Hawtin:
This question appears to have given some the impression that calling System.setSecurityManager(null); is okay. ... In case anyone has any doubts, changing global state in an applet will affect all applets in the same process. Clearing the security manager will allow any unsigned applet to do what it likes. Please don't sign code that plays with global state with a certificate you expect anyone to trust.
Edit 1:
Here is the source of the simple applet used in that demo. For some reason when I originally uploaded it, I decided the source was not relevant. OTOH 3 people have now asked to see the source, for one reason or another. When I get a round tuit I'll upload the source to my site. In the mean time, I'll put it here.
package org.pscode.eg.docload;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;
import java.security.*;
/** An applet to display documents that are JEditorPane compatible. */
public class DocumentLoader extends JApplet {
JEditorPane document;
#Override
public void init() {
System.out.println("init()");
JPanel main = new JPanel();
main.setLayout( new BorderLayout() );
getContentPane().add(main);
try {
// It might seem odd that a sandboxed applet can /instantiate/
// a File object, but until it goes to do anything with it, the
// JVM considers it 'OK'. Until we go to do anything with a
// 'File' object, it is really just a filename.
File f = new File(".");
// set up the green 'sandboxed page', as a precaution..
URL sandboxed = new URL(getDocumentBase(), "sandbox.html");
document = new JEditorPane(sandboxed);
main.add( new JScrollPane(document), BorderLayout.CENTER );
// Everything above here is possible for a sandboxed applet
// *test* if this applet is sandboxed
final JFileChooser jfc =
new JFileChooser(f); // invokes security check
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
jfc.setMultiSelectionEnabled(false);
JButton button = new JButton("Load Document");
button.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
int result = jfc.showOpenDialog(
DocumentLoader.this);
if ( result==JFileChooser.APPROVE_OPTION ) {
File temp = jfc.getSelectedFile();
try {
URL page = temp.toURI().toURL();
document.setPage( page );
} catch(Exception e) {
e.printStackTrace();
}
}
}
} );
main.add( button, BorderLayout.SOUTH );
// the applet is trusted, change to the red 'welcome page'
URL trusted = new URL(getDocumentBase(), "trusted.html");
document.setPage(trusted);
} catch (MalformedURLException murle) {
murle.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (AccessControlException ace) {
ace.printStackTrace();
}
}
#Override
public void start() {
System.out.println("start()");
}
#Override
public void stop() {
System.out.println("stop()");
}
#Override
public void destroy() {
System.out.println("destroy()");
}
}
Related
I'm experimenting with Weebly, and I'm currently trying to add an arbitrary swing program to the Weebly editor. I have tried two approaches thus far, as shown here:
1: (Note: - replaces < and >)
-embed height=400 width=400 src="siteName/uploads/someNumbers/testapplet.class"--/embed-
2: (Same substitution as above)
-applet codebase="siteName/uploads/someNumbers" code="testapplet.ckass" width=400 height=400--/applet-
Upon publishing and viewing the page, the first one says I need a plugin to display the content, and the second one says my security preferences won't let me run java on the site, whereas I can run java pretty much everywhere else just fine.
What should I do to make this work? This could include some of the following:
Modifying my program (i.e. the java code itself)
Modifying how I upload the program (i.e. .class vs .jar)
Modifying how I display the program (i.e. the actual -applet- or -embed-)
For reference, here is the java code- just a basic JButton and JLabel, with the JLabel's value increasing upon each click of the button:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class TestApplet extends JApplet
{
static int x = 0;
static JLabel l = new JLabel(x+"");
public void init()
{
setLayout(new FlowLayout());
JButton b = new JButton("Button");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
x++;
l.setText(x+"");
}
});
add(b);
add(l);
}
}
Sign in to weebly and click on the edit button next to your site name
On the "Elements" tab on the top, go to "Multimedia" and drag a file element onto your page.
Follow directions to upload your .class file. Name should be lowercase.
Hit the publish button and go to your published page.
Remember your .class file? Right-click on it and copy the link address or link location.
Go back to editing your weebly page.
On the "Elements" tab, go down to "More" and drag in the "Custom HTML" element.
Click to edit the custom HTML element- this is where we are going to put our applet code.
If my link location to my .class file was http://www.johndoe.com/uploads/3/3/2/6/3326331/countme.class, my applet code would read:
<applet codebase="http://www.johndoe.com/uploads/3/3/2/6/3326331" code="countme.class" width=something height=something></applet>
The idea is that the codebase tells the browser where to look for a .class file and the code itself tells it whick .class it is.
10. Publish again, and your applet should appear.
I haven't tried it personally, but I had a chat with a support support staff and they affirmed this method.
All the best!
The GWT web app I'm building has a page where users can upload CSV files. The upload code uses the Moxieapps GWT Uploader, which mostly works great.
However, I've discovered a strange scenario, where navigating away from the page and back to it adds the upload button again. So the third time I visit the page, the upload section will look like this:
And the relevant part of the generated HTML viewed in an inspector shows that both the input and the div containing the "button" get added over and over (though there is only ever one dropzone):
I've gone over my code many times to see whether I was doing something that could be causing this, but haven't found anything. You don't actually manually add the button or the input; this is done automatically by the framework. The fileUploader gets initialised only once (this being GWT client code, I've debugged using the inspector as well as logging statements to the console to confirm this):
fileUploader.setButtonDisabled(true).setFileTypes("*.csv")
.setUploadURL(getBaseUrl() + "/fileUpload.upload")
.setButtonText("<span class=\"buttonText\">Select CSV file to upload</span>")
.setFileSizeLimit(FILE_SIZE_LIMIT)
.setButtonCursor(CustomUploader.Cursor.HAND)
.setButtonAction(CustomUploader.ButtonAction.SELECT_FILE)
.setUploadProgressHandler(new UploadProgressHandler() {...})
.setUploadSuccessHandler(...)
// etc. with other handlers
The method setButtonText() is called from a couple of other places, and the text changes as it should, but only on the last button (if there are several). Otherwise, there's nothing in my code that could possibly be adding the button as far as I can tell.
Has anyone else encountered this issue? Is there some property I need to set to prevent this? Could it be a bug in the moxieapps code?
After writing out my question, and adding "Could it be a bug in the moxieapps code?" at the end, I followed up on that suspicion, and it turns out that it is indeed a bug in the org.moxieapps.gwt.uploader.client.Uploader class.
The input and the "select file" button are added in the onLoad() method of that class without a check whether they may have been added already.
It looks like there hasn't been any active development on this framework for some time, so I thought it was time for a custom override version. I've tested this and it works:
package yourpackagename.client.override;
import java.util.Iterator;
import org.moxieapps.gwt.uploader.client.Uploader;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetCollection;
/**
* The sole reason this class exists is to fix a bug in the moxieapps uploader
* (org.moxieapps.gwt.uploader-1.1.0.jar) where it adds a new upload input and
* button each time its <code>onLoad()</code> method is called, i.e. every time
* you navigate away from the page and then back to it.
*/
public class CustomUploader extends Uploader {
#Override
protected void onLoad() {
boolean hasFileUploadAlready = false;
WidgetCollection children = getChildren();
for (Iterator<Widget> iterator = children.iterator(); iterator.hasNext();) {
Widget eachWidget = iterator.next();
if (eachWidget instanceof FileUpload) {
hasFileUploadAlready = true;
}
}
// Only call the super method if there isn't already a file upload input and button
if (!hasFileUploadAlready) {
super.onLoad();
}
}
}
Instead of referencing the org.moxieapps.gwt.uploader.client.Uploader, I've changed the references to point to my custom uploader class, which will now check for an existing FileUpload child widget, and simply skip the original onLoad() code if it finds such a widget.
Might be a bit of a crowbar approach, but it works (and in my case, changing the maven-managed JAR file is not very practical). Hopefully, this will be useful to anyone else coming across this problem.
I know in scripting languages like Python that this is possible but I know that Java applets can't access other servers other than their own.
I don't know/think I can get this applet signed. Is there a way to use PHP to do what I want to accomplish?
I also know that this code will go to google.com
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
public class tesURL extends Applet implements ActionListener{
public void init(){
String link_Text = "google";
Button b = new Button(link_Text);
b.addActionListener(this);
add(b);
}
public void actionPerformed(ActionEvent ae){
//get the button label
Button source = (Button)ae.getSource();
String link = "http://www."+source.getLabel()+".com";
try
{
AppletContext a = getAppletContext();
URL u = new URL(link);
// a.showDocument(u,"_blank");
// _blank to open page in new window
a.showDocument(u,"_self");
}
catch (MalformedURLException e){
System.out.println(e.getMessage());
}
}
}
That is assuming that source.getLabel() is "google"
But how would I get the source html of that page?
The source html is dynamic and is updated every few seconds or miliseconds. But, the html is also updated, so I can still read the dynamic content directly from the html. I already did this in vb.net, but now I need to port it to Java, but I can't figure out how to access a page's html source; that's why I'm asking.
AppletContext.showDocument opens a page in the browser, much like a hyperlink in HTML or a similar call in JavaScript would do. Under the Same Origin Policy you will not have access to this page if it is from a different site, even if the page is in an iframe.
Some sites may have a crossdomain.xml policy file that allows access if you were to read the contents of the java.net.URL directly. However, www.google.com appears to be using a restricted form that I don't believe is currently supported by the Java PlugIn.
Someone will probably suggest signing your applet, which turns off the "sandbox" security feature of Java. You would then need to persuade your users to trust your ability to publish safe signed code.
I am getting the java.lang.SecurityException: Permission denied: file:////Videos/public/scripts/screenshot.jar when I try to use an applet.
Here is the applet code:
<applet code="Screenshot" archive="file:////Videos/public/scripts/screenshot.jar" width="100px" height="100px">
</applet>
How do I fix it and what the problem even means?
EDIT:
From what I see I need to sign the applet. Could some one explain how and why this is done? The site provided does a bad job explaining it because it doesn't even address the fact that I am embedding this into my site and want every client to use it and not have to sign anything. Just click run.
EDIT2:
The code of the app itself:
/*
By Bavo Bruylandt (Http://www.realapplets.com")
*/
// and now The inevidable "Hello World" example :)
// tell the compiler where to find the methods you will use.
// required when you create an applet
import java.applet.*;
// required to paint on screen
import java.awt.*;
// the start of an applet - HelloWorld will be the executable class
// Extends applet means that you will build the code on the standard Applet class
public class Screenshot extends Applet
{
// The method that will be automatically called when the applet is started
public void init()
{
// It is required but does not need anything.
}
// This method gets called when the applet is terminated
// That's when the user goes to another page or exits the browser.
public void stop()
{
// no actions needed here now.
}
// The standard method that you have to use to paint things on screen
// This overrides the empty Applet method, you can't called it "display" for example.
public void paint(Graphics g)
{
//method to draw text on screen
// String first, then x and y coordinate.
g.drawString("Hey hey hey",20,20);
g.drawString("Hellooow World",20,40);
}
}
It all depends on what is your applet trying to do, is it accessing the filesystem for example. Is it a signed applet or not? Applets run in a special sandbox by default with limited permissions.
You would have to check out more info on Applet security, for starters have a look into Informit article here: http://www.informit.com/articles/article.aspx?p=433382&seqNum=2
EDIT:
Try to add a policy file eg.
/* AUTOMATICALLY GENERATED ON Tue Apr 16 17:20:59 EDT 2002*/
/* DO NOT EDIT */
grant {
permission java.security.AllPermission;
};
named eg. java.policy.applet and place it on your classpath. Have a look at this question here about the policy files: Where to place java applet policy file?
There are a lot of resources on this already but I just can't seem to get it to work. What am I doing wrong? The jar file is at:
http://www.alexandertechniqueatlantic.ca/multimedia/AT-web-presentation-imp.jar
And the code I am using to embed is:
<APPLET ARCHIVE="multimedia/AT-web-presentation-imp.jar"
CODE="ImpViewer.class"
WIDTH=100%
HEIGHT=100%>
</APPLET>
The test page I am using is at:
http://www.alexandertechniqueatlantic.ca/test.php
When I download the jar it runs fine, so I am certain the problem is only with the html embedding. Pleas help!
Also, I get the following error:
java.lang.ClassCastException: ImpViewer cannot be cast to
java.applet.Applet
java.lang.ClassCastException: ImpViewer cannot be cast to java.applet.Applet
The 'applet' is not an applet.
BTW - nice UI. Like the way the red splash fades in to the 'Welcome Introductory Workshop' page. Very smooth.
Launch it from a link using Java Web Start (& please don't try and cram such a beautiful UI into a web page).
If the client insists on the GUI being crammed into a web site then (slap them for me &) try this hack.
/*
<APPLET
ARCHIVE="AT-web-presentation-imp.jar"
CODE="ImpViewerApplet"
WIDTH=720
HEIGHT=564>
</APPLET>
*/
import java.awt.*;
import java.applet.*;
import java.util.*;
public class ImpViewerApplet extends Applet {
public void init() {
setLayout(new BorderLayout());
Window[] all = Window.getWindows();
ArrayList<Window> allList = new ArrayList<Window>();
for (Window window : all) {
allList.add(window);
}
String[] args = {};
ImpViewer iv = new ImpViewer();
iv.main(args);
all = Window.getWindows();
for (Window window : all) {
if (!allList.contains(window) && window.isVisible()) {
if (window instanceof Frame) {
Frame f = (Frame)window;
Component[] allComp = f.getComponents();
Component c = f.getComponents()[0];
f.remove(c);
f.setVisible(false);
add(c);
validate();
}
}
}
}
}
The emphasis is on the word 'hack'.
The Frame will flash onto screen before disappearing.
It will only work at 720x564 px, unlike the java.awt.Frame which was resizable to any size. But then, your '100%' width/height was being a bit optimistic anyway. Some browsers will honour those constraints, others will not.
It took a bit of effort, but your ImpViewer class has the following definition:
public class ImpViewer extends ImWindow
implements Printable, Runnable
{
[...]
ImpViewer is NOT an Applet like it needs to be, but is instead an ImWindow. It should inherit from either Applet or perhaps ImApplet.
At either rate, Andrews idea of using Java Web Start is legit. The app you have looks more like a desktop app.
An Applet is a Java component which handles the right calls to show up embedded in a web page. The product you have (the JAR file) contains everything necessary to run the program; however, it does not have the correct interface (the applet) for running that program embedded in a web page.
Talk to the author of the product (of if that author is not available, look for documentation) and see if a applet interface is available. Perhaps it is only a matter of using a different class name. If it looks like such an interface is not available, then no one has done the necessary work to make it "embeddable" in a web page. Without knowing your product in more detail, it's not easy to determine if the effort to create an Applet interface into the product is easy or not.
If you don't have the source code, then the amount of effort to develop an Applet interface to what you have is even greater than the unknown amount of effort it would have been with the source code.
There are a few products that do allow applications to be viewed and controlled from a web browser, even when the application in question wasn't designed to be embedded in a web page. These products tend to be expensive and proprietary; but, if it is truly mission-critical (and if it makes enough money) then the expense and effort might be bearable. With such a solution, the web browser actually opens a window into a configured "application server" which launches the application in full screen mode every time the connection is established. Yes, it is an odd architecture; however, such an odd architecture exists purposefully as that's really the only way possible to do some things when the application can't run in other environments.
Look to Citrix for such a solution in the event that you can afford it (remember there's extra windows licenses involved) and you can tolerate it's performance and quirks.