Kerberos is a single sign on solution. AFAICT, it is the only one that solves the problem completely: You confirm that you are who you say you are, and the remote side confirms that it is who you think it is. It doesn’t work over he public internet only due to the fact that most corporate firewalls block the ports it needs. So we want to be able to do Kerberos, or its equivalent from the browser.
Category Archives: Sysadmin
Java Web Applications in Fedora
Fedora and Debian play the role where many chaotic projects get a degree of charm school: they learn to play nice with a lot of other projects. In Fedora, as near as I can tell, there is only one Java based web application packages as part of the distribution: Dogtag, the Public Key Infrastructure server. As we look at how PKI should look in the future, the dearth of comparable applications packaged for Fedora leaves us with the opportunity for defining a logical and simple standard packing scheme. While I am not there yet, this post is the start of my attempts to organize my thoughts on the subject. I’m looking for input.
Group Delegation in Unix
One thing that is missing in traditional Unix systems is the ability to let a non root user manage group membership. Unix was built around several simple concepts. One of those was: everything is a file. Using this principle, we can specify how group delegation would have worked.
Talking to Dogtag PKI via curl
As I dig deeper into the Dogtag code, I find I want to be able to talk to the web server from the command line the same way I did when for IPA work. Since Dogtag is certificate based, and the version of curl included in Fedora has NSS build in, I used the NSS/Certificate approach.
Java as a scripting language
When developing in Python or Perl, it is very common to start with an executable script, and to edit/run/edit/run. Java is slowed down by the cycle of edit/compile/run. Here’s a proof of concept of coding in Java like you do in Python.
Updating a certificate for a FreeIPA web server
As I install, uninstall, and re-install FreeIPA, I start getting:sec_error_reused_issuer_and_serial. This used to be a minor annoyance, solved by clearing the certificates out of, and restarting, the browser. Recent versions of Firefox have complained even after doing this, leading to the current approach: clear your browser cache. Instead, you can update the certificate on the web server, and this should give you a cert with a new serial number, and avoid the error message.
IPAddress for local Virtual Machines
When running Fedora as a KVM/Qemu host for virtual machines, you have the issue that you don’t know the IP Address for a virtual machine once you create it. IP addresses that are assigned via
The MAC Address is in the config file saved in
/etc/libvirt/qemu/$VMNAME.xml
Once you start the virtual machine, you can fetch the IP Address from the DHCP lease file in:
/var/lib/dnsmasq/dnsmasq.leases
To correlate the two:
#!/bin/bash VMNAME=$1 MAC=`cat /etc/libvirt/qemu/$VMNAME.xml | xml2 | awk 'BEGIN{FS="="} /mac..address/ {print $2}'` IP=`grep $MAC /var/lib/dnsmasq/dnsmasq.leases | cut -d' ' -f3` #$VMNAME has MAC $MAC and IPAddress $IP echo $IP
This must be called as root or via sudo.
UPDATE:
Chris Lalancette notes that the cannonical version of the MAC address can be found using
virsh -c qemu:///system dumpxml $VMNAME
Binary Java Runner
I’ve been recently thinking about the scripts that are used to run Java processes. Firing a script interpreter and running a slew of processes before running your program seems really inefficient. Additionally, programs meant to run on a Fedora system can make a few assumptions that general Java programs can’t.
Jar files should be in /usr/share/java or /usr/lib/java.We don’t want people putting files all over the place. Most of the scripts are doing classpath related operations.
Here is my Sample code
class Hello{ public static void main(String[] args){ for (int i =0 ; i < args.length; i++){ System.out.println ("Hello "+args[i]); } } }
Which I can compile into a Jar file pretty easily. I'll cll the jar hello.jar
int main() { char *const argv[] = {"/usr/bin/java","-cp","hello.jar","Hello"}; char *newenviron[] = { NULL }; execve(argv[0], argv,newenviron); perror("execve"); return 0; }
This serves as a starting point.
But, really, do we want to have to ship a Jar file and a separate executable? For command line utilities, the basic classes that it requires should be statically bound into the application. We can convert the Jar file into data an link it into the application:
ld -r -b binary -o ant-launcher.o /usr/share/java/hello.jar cc runjava.c hello.o -o runjava
Now is where things get interesting.
First, we need a way to load this Embedded Jar file in as a class. As a proof of concept, the C program can read the data section and spit it out to a jar file.
const char * temp_file_template = "hello.jar.XXXXXX"; char * temp_file = "hello.jar.XXXXXX"; void build_jar(){ temp_file = malloc(strlen(temp_file_template)+1); memset(temp_file, 0, strlen(temp_file_template)+1); strcat(temp_file, temp_file_template); int retval = mkstemp(temp_file); int fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC ,S_IRWXU ); if (fd < 0){ perror("main"); return; } ssize_t sz = write ( fd, &_binary_hello_jar_start, (ssize_t)&_binary_hello_jar_size); if (sz < 0){ perror("Write"); } close(fd); }
This produces the same output as if we had run it from the initial example.
But, this is wasteful. This example will litter a copy of the jar file into your directory. You can't delete it when you are done; exec does not return to your code.
So the next step is, instead of running using exec, run using JNI.
/*run the executable using an embedded JVM*/ void run_embedded(){ JNIEnv *env; JavaVM *jvm; JavaVMInitArgs vm_args; JavaVMOption options[2]; int option_count; jint res; jclass main_class; jobject javaGUI; jmethodID main_method; jthrowable exception; jobjectArray ret; int i; const char * classpath_prefix = "-Djava.class.path="; int classpath_option_length = strlen(classpath_prefix) + strlen(temp_file) + 1; char * classpath_option = malloc(classpath_option_length); memset(classpath_option, 0, classpath_option_length); strcat(classpath_option, classpath_prefix); strcat(classpath_option, temp_file); option_count=1; //set to 2 for jni debugging options[0].optionString = classpath_option; options[1].optionString = "-verbose:jni"; /* Specifies the JNIversion used */ vm_args.version = JNI_VERSION_1_6; vm_args.options = options; vm_args.nOptions = option_count; /* JNI won'tcomplain about unrecognized options */ vm_args.ignoreUnrecognized = JNI_TRUE; res = JNI_CreateJavaVM(&jvm,(void **)&env,&vm_args); free(classpath_option); if (res < 0 ){ exit(res); } const char * classname = "Hello"; main_class = (*env)->FindClass(env, classname); if (check_error(main_class,env)) { return; } main_method = (*env)->GetStaticMethodID(env,main_class,"main", "([Ljava/lang/String;)V"); if (check_error(main_method,env)) { return; } char *message[5]= { "first", "second", "third", "fourth", "fifth"}; jstring blank = (*env)->NewStringUTF(env, ""); jobjectArray arg_array = (jobjectArray)(*env)->NewObjectArray (env,5, (*env)->FindClass(env,"java/lang/String"), blank); if (check_error(arg_array,env)) { return; } for(i=0;i<5;i++) { jstring str = (*env)->NewStringUTF(env, message[i]); (*env)->SetObjectArrayElement ( env,arg_array,i,str); } jobject result = (*env)->CallStaticObjectMethod(env, main_class, main_method, arg_array ); if (check_error(result,env)) { return; } }
Note that we have now linked against a version of the JVM, and that commits us to a given JDK. This is just a proof-of-concept; This whole copy the Jar approach is just a stepping stone.
What we really want is a classloader which plays by the following rules:
- lets the rt.jar classloader safely load the basic java, javax, and other JRE classes as a normal executable
- makes sure that all the classes for our application get loaded from our specified jar file
- reads our specified jar file directly out of the elf section of our binary executable
I appears to me that the standard classloading approach is fine for our needs with one exception: we can't treat an ELF file as if it were a Jar file. If we could do that, we could throw argv[0] on the front of the -Djava.class.path command line switch and be off and running. This would have the added benefit of creating a classloader extension that could be used from other Java programs as well. I'm currently thinking it should be of the form: file+elf://path-to-file/linked_jarfile_name
as that format would allow us to link in multiple jar files.
However, to be really efficient, we don't want to have to pay the price for the OS file operations (open, read) again, since the jar file is already loaded into memory. We should be able to create a protocol which tells the classloader: use this InputStream to load the class, and the JNI code can then pass the input stream.
systemd for tomcat
The systemd author insists that everything should be callable from an elf binary? Who am I to argue? Actually, I like the idea. So, how would we go about running the tomcat startup?
Automount and home directory creation
NFS is the NAS equivalent of Democracy: the worst implementation except for all the others. If you want a remote home directory for your users, chances are you’ve contemplated Automount as the solution for it. I’ve been working on Automount support for the web UI in FreeIPA. Here’s the concept. When you add a user, you want to delay creation of the users home directory on some subset of Network Devices. This is a tricky problem to solve. Here’s why.
Continue reading