Wikantik's JAAS-based architecture is well-suited for OAuth integration. The key insight is that passwords are optional in the user database, so OAuth users can be created without passwords and never use password-based login.
1. 1. New Java Classes (~6-8 files)
| File | Purpose |
|---|---|
OAuthLoginModule.java | JAAS LoginModule that validates tokens and creates/links users |
OAuthCallbackHandler.java | Passes OAuth token to LoginModule via JAAS callbacks |
OAuthCallback.java | Custom JAAS Callback for OAuth data |
OAuthCallbackServlet.java | Handles /wiki/oauth/callback redirect from providers |
GoogleOAuthProvider.java | Validates Google tokens, fetches user info |
GitHubOAuthProvider.java | Validates GitHub tokens, fetches user info |
OAuthUserInfo.java | DTO for user info from providers |
1. 2. UI Modifications
LoginContent.jsp: Add "Login with Google" and "Login with GitHub" buttons
Buttons link to /wiki/oauth/google?redirect=... and /wiki/oauth/github?redirect=...
# OAuth SSO Configuration
jspwiki.oauth.enabled=true
jspwiki.oauth.autoCreateUsers=true
# Google OAuth 2.0 / OpenID Connect
jspwiki.oauth.google.enabled=true
jspwiki.oauth.google.clientId=YOUR_CLIENT_ID
jspwiki.oauth.google.clientSecret=YOUR_CLIENT_SECRET
# GitHub OAuth 2.0
jspwiki.oauth.github.enabled=true
jspwiki.oauth.github.clientId=YOUR_CLIENT_ID
jspwiki.oauth.github.clientSecret=YOUR_CLIENT_SECRET
1. 4. Dependencies (pom.xml)
google-oauth-client or oltu.oauth2)# User clicks "Login with Google" on LoginContent.jsp
↓
2. OAuthCallbackServlet redirects to Google consent screen
↓
3. User authenticates with Google
↓
4. Google redirects to /wiki/oauth/callback?code=...&state=...
↓
5. OAuthCallbackServlet:
- Exchanges code for access token
- Fetches user info (email, name, provider ID)
- Creates OAuthCallbackHandler with token data
- Calls AuthenticationManager with OAuthLoginModule
↓
6. OAuthLoginModule.login():
- Gets token data from callback handler
- Looks up user by email in UserDatabase
- If not found: creates new UserProfile (no password)
- Adds WikiPrincipal to principals set
↓
7. WikiSession.actionPerformed():
- Receives LOGIN_AUTHENTICATED event
- Sets session status to AUTHENTICATED
- Injects user profile principals
- Injects group memberships
↓
8. Redirect to original page
// In OAuthLoginModule.login()
UserProfile profile;
try {
profile = db.findByEmail(oauthUserInfo.getEmail());
} catch (NoSuchPrincipalException e) {
// Create new user
profile = db.newProfile();
profile.setLoginName(generateLoginName(oauthUserInfo));
profile.setEmail(oauthUserInfo.getEmail());
profile.setFullname(oauthUserInfo.getName());
profile.setPassword(null); // No password for OAuth users
// Store OAuth metadata in custom attributes
profile.getAttributes().put("oauth.provider", "google");
profile.getAttributes().put("oauth.providerId", oauthUserInfo.getId());
db.save(profile);
}
google_123456789 (provider + ID)john.smith (email local part)jsmith (truncated)1. 1. Password-less Users Work Out-of-Box
UserDatabaseLoginModule.login() line 86 checks:
if (storedPassword != null && db.validatePassword(...))
OAuth users with null password bypass password validation entirely.
1. 2. Session Establishment is Automatic
Just fire the event and WikiSession handles everything:
fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, principal, session);
1. 3. Configuration is Already Flexible
DefaultAuthenticationManager.initLoginModuleOptions() loads all jspwiki.loginModule.options.* properties and passes them to the LoginModule.
1. 4. User Database Abstraction Works Well
The JDBCUserDatabase supports:
findByEmail(String) - Look up existing userssave(UserProfile) - Create new users| Challenge | Solution |
|---|---|
| Same person, multiple providers | Link by email; store provider info in attributes |
| Incomplete profile data | Compute full name from email; prompt for completion |
| Token expiry | Store refresh token (encrypted) in attributes |
| Logout coordination | Clear local session; optionally revoke provider token |
| Account security | Require email verification; admin account linking tool |
| Phase | Effort | Description |
|---|---|---|
| Core OAuth | 3-4 days | LoginModule, CallbackHandler, Servlet, Providers |
| User provisioning | 1-2 days | Account creation, email linking, attributes |
| UI | 1 day | Login buttons, styling |
| Configuration | 0.5 day | Properties, documentation |
| Testing | 2-3 days | Unit tests, integration tests |
| Total | ~8-10 days | For experienced developer |
OAuthCallbackServlet handles:
OAuthLoginModule handles:
This separation keeps OAuth protocol details out of JAAS and allows the LoginModule to focus on user management.
| File | Change |
|---|---|
wikantik.properties | Add OAuth configuration properties |
LoginContent.jsp | Add OAuth login buttons |
web.xml | Register OAuthCallbackServlet |
pom.xml | Add OAuth dependencies |
WikiServletFilter.doFilter() line 120DefaultAuthenticationManager.login() lines 156-240WikiSession.getWikiSession() line 483WikiSession.actionPerformed() line 244/auth/user/UserProfile.java/auth/user/DefaultUserProfile.java/auth/user/UserDatabase.java/auth/user/JDBCUserDatabase.java/auth/login/AbstractLoginModule.java/auth/login/UserDatabaseLoginModule.java lines 66-108/auth/login/WikiCallbackHandler.javaDefaultAuthenticationManager.initialize() line 110DefaultAuthenticationManager.initLoginModuleOptions() line 375/wikantik-war/src/main/webapp/Login.jsp/wikantik-war/src/main/webapp/templates/default/LoginContent.jspImplementing OAuth SSO for Google/GitHub in Wikantik is architecturally straightforward due to:
The main work is implementing the OAuth protocol (token exchange, API calls) and user provisioning logic. The Wikantik authentication infrastructure supports this cleanly.