MongoDB Media Server

Code available on GitHub

The included code is a show case, not a full media server! This is also a somewhat older project, if I missed something feel free to add an issue on GitHub.

So I’ve been going through playground folder on my hard disk. That’s the place I store all my projects I did for showcasing or simply to play around with new things.
And I found a little something I did about a year ago for the Senacor DevCon. It’s a small media server project based on Spring Data and MongoDB.

I am releasing it because I think it’s a great example for the simplicity of Spring Data combined with SpringMVC.
NOTE: There’s a a python script included to import your MP3s into the database. You will need Mutagen on your machine to use it.

All the interesting things happen in the LibraryRessource. Let’s take a look at the most important parts.
The things we nee to work with are the SongRepository (a simple Spring Data repository), MongoTemplate (here be CRUD) and the GridFsTemplate, which is required for documents >16 MB (see GridFS).

@Controller
public class LibraryRessource {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private SongRepository songRepository;

Most of the @RequestMapping-annotated classes should be self explaining so I will foxus on the “tricky” ones.
getSongs(..)_ is responsible for assembling the Song-JSON documents which contain a link to the GridFS-file to start streaming. To be able to assemble I have to git hold of the MD5-checksum to reference it.

    @RequestMapping(value = "/library/songs", method = RequestMethod.GET, produces = "application/json")
    public @ResponseBody Songs getSongs(HttpServletRequest request) {
        Songs songs = new Songs();
        for (Song song: songRepository.findAll()) {
            GridFSDBFile file = gridFsTemplate.findOne(query(where("_id").is(song.getFileId())));
            String requestBase = request.getRequestURL().toString().split("song")[0];
            song.setFileHref(requestBase + "files/" + file.getMD5());
            songs.addSong(song);
        }
        return songs;
    }

The actual streaming is done in getFile(..). Thanks to the fluent-API of GridFsTemplate it turned out that the trickiest part of my application could be done in a single line of code. The only thing to be aware of is that getting hold of the HttpServletResponse used by your request is by adding it to the method signature.


    @RequestMapping(value = "/library/files/{md5}", method = RequestMethod.GET)
    public void getFile(HttpServletResponse response, @PathVariable("md5") String md5) throws IOException {
        gridFsTemplate.findOne(query(where("md5").is(md5))).writeTo(response.getOutputStream());
    }

The generated URLs can be accessed using VLC.

Advertisement

Using Spring Security 3 with Wicket 6-AuthRoles and JavaConfig and a little Servlet 3

Spring Security is a great framework. It unifies a lot of different authentication mechanisms into a pretty decent package. The only part that wasn’t really up to current Spring-standards was the lack of full java config support. In July they finally released the first fully java config enabled version.

In this blog post I’d like to show how to integrate this new version with Wicket 6-AuthRoles.

The project

I put all the code up on GitHub, clone it and you are ready to go. It shouldn’t be a big surprise that you have to use a Servlet 3 container. I tested the application on Tomcat 7 and Jetty 9, worked without a hitch.

How Spring and Servlet 3 Interact

Servlet 3 provides one of the most fundamental changes. It made web.xml optional. To achieve this the container will scan each war for an implementation of javax.servlet.ServletContainerInitializer to get everything going. Spring provides such a implementation with the SpringServletContainerInitializer. When it is discovered by the container it will then scan the class path for implementations of WebApplicationInitializer. And that’s where we do our stuff.

Servlet 3 Bootstrap

The class AppInitializer contains the whole code required to bootstrap the application. The only really interesting part is how to actually register the Wicket-filter. That cost me some time to figure out but the following snipped does the trick:


        WicketFilter wicketFilter = new WicketFilter(new WicketApplication()) {
            @Override
            public void init(boolean isServlet, FilterConfig filterConfig) throws ServletException {
                setFilterPath("");
                super.init(isServlet, filterConfig);
            }
        };
        FilterRegistration.Dynamic wicketFilterReg = servletContext.addFilter("wicketFilter", wicketFilter);

Auth Roles

Wicket-AuthRoles provide a complete set of annotations to cover all scenarios of authorization. In my demo application I only use @AuthorizeInstantiation.

One important thing to note is that Spring Security prepends ROLE_ to all role names. So instead of writing @AuthorizeInstantiation(Roles.USER) you will have to use @AuthorizeInstantiation(“ROLE_USER”).

Getting AuthRoles to work you need to provide a custom WebSession-implementation:


public class UserAuthenticatedWebSession extends AuthenticatedWebSession {    
    public UserAuthenticatedWebSession(Request request) {
        super(request);
    }

    @Override
    public boolean authenticate(String username, String password) {
        throw new UnsupportedOperationException("You are supposed to use Spring-Security!!");
    }

    @Override
    public Roles getRoles() {
        Roles roles = new Roles();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        for (GrantedAuthority authority : authentication.getAuthorities()) {
            roles.add(authority.getAuthority());
        }
        return roles;
    }

}

The authenticate method is not required as Spring Security is going to take care of that. The only thing we have to do in here is to provide a getRoles-implementation which uses the SecurityContextHolder

Now we have to change the WebApplication to extend AuthenticatedWebApplication and override init, getWebSessionClass and getSignInPageClass:


@Override
public void init() {
    super.init();
    getComponentInstantiationListeners().add(new SpringComponentInjector(this));
    getSecuritySettings().setAuthorizationStrategy(new AnnotationsRoleAuthorizationStrategy(this));
    mountPage("/home", HomePage.class);
    mountPage("/login", SignInPage.class);
}

We also have to specify the /login-mountpoint this should point to a Wicket-page with the following content:


<form method="POST">
    <input type="text" id="username" name="username"/>
    <input type="password" id="password" name="password"/>
    <input type="submit" value="submit"/>
</form>

The form-submit will NOT be handled by Wicket but by the Spring Security filter!

Spring Security

The final piece of the puzzle is the Spring Security configuration.

In AppInitializer I added the following code to bootstrap the Spring context and the security filter:


    AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
    root.register(SpringSecurityConfiguration.class);
    FilterRegistration.Dynamic springSecurityFilterChainReg = servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class);
    springSecurityFilterChainReg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.ERROR, DispatcherType.REQUEST), false, "/*");
    servletContext.addListener(new ContextLoaderListener(root));

The actual configuration happens in SpringSecurityConfiguration:


@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeUrls()
                .antMatchers("/favicon.ico")
                    .permitAll()
                .antMatchers("/**")
                    .hasRole("USER")
                    .and()
                    .formLogin()
                        .loginPage("/login")
                        .permitAll();
    }

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("testuser")
                    .password("password")
                    .roles("USER");
    }
}

I use configure to tell spring security to allow unrestricted access to favicon.ico. Then I tell it ti restrict access to all other URLs to users with the role USER (reminder: this translates to ROLE_USER when used in AuthRoles-annotations). The last step is to add a custom formLogin to use the mount point from before.

In registerAuthentication I add a simple in-memory-authentication. Here you can now add all the other fancy stuff.

Get it while it’s hot: https://github.com/codepitbull/wicket-servlet3-springsecurity

Have fun.

Vert.X 2.0.0 in IntelliJ IDEA

Well, that was fast. After posting my last post I saw that vert.x 2.0.0.final came out last night. Tough luck but sitting on the train I got time enough to provide an update.

Project setup

Follow these to create a basic gradle-project with an example verticle. After doing a gradle clean build idea you can now import the project into Idea.

Running

The examples provided only show how to run this project from the command line. I am a lazy ass and like to run my stuff from the IDE.

To achieve this add a new java-module using File>New Module. Open Open Module Settings, select the newly created module and add contents of the lib-directory from your freshly downloaded vert.x-2.0.0-final-archive in the Dependencies-tab.

Create a new Run-Config and:

  • set Main Class to org.vertx.java.platform.impl.cli.Starter
  • set Program arguments to runmod com.yourcompany~your-module~1.0 -cp <path-to-your-project>/out/production/<module-name>
  • set Use classpath of module to the module we just created and added the vert.x-libs to

Hit run.

Enjoy.

Serving static content with Jetty 9

I am currently (again) doing a lot of JavaScript related stuff. My favorite IDE (IntelliJ IDEA) has stellar support for this crappy language. The only thing I needed was a SMALL web server to play around with static html and some JavaScripts. The quickest way was to use Jetty 9 as it can be found on all of my development machines.

Just add a Jetty9-RunConfig in IDEA (or Eclipse, if you have to) and create static.xml with the following content in $JETTY_HOME/webapps.

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd">

<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  <Set name="contextPath">/static</Set>
  <Set name="resourceBase">/path/to/your/document/root/</Set>
  <Set name="handler">
    <New class="org.eclipse.jetty.server.handler.ResourceHandler">
      <Set name="cacheControl">no-cache</Set>
    </New>
  </Set>
</Configure>

Don’t forget to adjust resourceBase to your liking.

Note: I also disabled caching in this example.

Back on the Blog, again

As you might have noticed: It’s been pretty quiet around my blog.

I took an offer to write a book about my favorite web framework, Apache Wicket.

Together with a bunch of articles I did for both it-republik (Wicket 1.5 Wicket 6 and the German Java Magazin_ (1, 2, 3, 4) I basically spent all my time writing about and coding Wicket. A few weeks ago I finally hit the last milestone of this year by attending the Plat_forms-Contest in Berlin, an experience I am going to write about soon.

Let’s keep it short:

  • I am again back on the blog.
  • I got a ton of notes I need to turn into posts.

Time to get going.

P.S.: I will do a few more articles in German. Looks like there is no good way to provide an article in two different languages on wordpress. This might lead to a few more changes to this blog.