001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 */ 012 013package org.nuxeo.ecm.core.api; 014 015import java.security.Principal; 016 017import javax.security.auth.login.LoginContext; 018import javax.security.auth.login.LoginException; 019 020import org.nuxeo.ecm.core.api.security.SecurityConstants; 021import org.nuxeo.runtime.api.Framework; 022 023/** 024 * Helper class to run code with an unrestricted session. 025 * <p> 026 * The caller must implement the {@link #run} method, and call {@link #runUnrestricted}. 027 * 028 * @author Florent Guillaume 029 */ 030public abstract class UnrestrictedSessionRunner { 031 032 protected String originatingUsername; 033 034 protected CoreSession session; 035 036 protected final boolean sessionIsAlreadyUnrestricted; 037 038 protected final String repositoryName; 039 040 /** True if a call to {@link #runUnrestricted} is in progress. */ 041 public boolean isUnrestricted; 042 043 /** 044 * Constructs a {@link UnrestrictedSessionRunner} given an existing session (which may or may not be already 045 * unrestricted). 046 * <p> 047 * Originating user is taken on given session. 048 * 049 * @param session the available session 050 */ 051 protected UnrestrictedSessionRunner(CoreSession session) { 052 this.session = session; 053 sessionIsAlreadyUnrestricted = isUnrestricted(session); 054 if (sessionIsAlreadyUnrestricted) { 055 repositoryName = null; 056 } else { 057 repositoryName = session.getRepositoryName(); 058 } 059 Principal pal = session.getPrincipal(); 060 if (pal != null) { 061 originatingUsername = pal.getName(); 062 } 063 } 064 065 /** 066 * Constructs a {@link UnrestrictedSessionRunner} given a repository name. 067 * 068 * @param repositoryName the repository name 069 */ 070 protected UnrestrictedSessionRunner(String repositoryName) { 071 session = null; 072 sessionIsAlreadyUnrestricted = false; 073 this.repositoryName = repositoryName; 074 } 075 076 /** 077 * Constructs a {@link UnrestrictedSessionRunner} given a repository name and an originating user name. 078 * 079 * @param repositoryName the repository name 080 * @param originatingUser the user name behind the system user 081 */ 082 protected UnrestrictedSessionRunner(String repositoryName, String originatingUser) { 083 session = null; 084 sessionIsAlreadyUnrestricted = false; 085 this.repositoryName = repositoryName; 086 this.originatingUsername = originatingUser; 087 } 088 089 public String getOriginatingUsername() { 090 return originatingUsername; 091 } 092 093 public void setOriginatingUsername(String originatingUsername) { 094 this.originatingUsername = originatingUsername; 095 } 096 097 protected boolean isUnrestricted(CoreSession session) { 098 return SecurityConstants.SYSTEM_USERNAME.equals(session.getPrincipal().getName()) 099 || (session.getPrincipal() instanceof NuxeoPrincipal && ((NuxeoPrincipal) session.getPrincipal()).isAdministrator()); 100 } 101 102 /** 103 * Calls the {@link #run()} method with an unrestricted {@link #session}. During this call, {@link #isUnrestricted} 104 * is set to {@code true}. 105 */ 106 public void runUnrestricted() { 107 isUnrestricted = true; 108 try { 109 if (sessionIsAlreadyUnrestricted) { 110 run(); 111 return; 112 } 113 114 LoginContext loginContext; 115 try { 116 loginContext = Framework.loginAs(originatingUsername); 117 } catch (LoginException e) { 118 throw new NuxeoException(e); 119 } 120 try { 121 CoreSession baseSession = session; 122 if (baseSession != null && !baseSession.isStateSharedByAllThreadSessions()) { 123 // save base session state for unrestricted one 124 baseSession.save(); 125 } 126 session = CoreInstance.openCoreSession(repositoryName); 127 if (loginContext == null && Framework.isTestModeSet()) { 128 NuxeoPrincipal principal = (NuxeoPrincipal) session.getPrincipal(); 129 if (principal instanceof SystemPrincipal) { 130 // we are in a test that is not using authentication 131 // => 132 // we're not stacking the originating user in the 133 // authentication stack 134 // so we're setting manually now 135 principal.setOriginatingUser(originatingUsername); 136 } 137 } 138 try { 139 run(); 140 } finally { 141 try { 142 if (!session.isStateSharedByAllThreadSessions()) { 143 // save unrestricted state for base session 144 session.save(); 145 } 146 session.close(); 147 } finally { 148 if (baseSession != null && !baseSession.isStateSharedByAllThreadSessions()) { 149 // process invalidations from unrestricted session 150 baseSession.save(); 151 } 152 session = baseSession; 153 } 154 } 155 } finally { 156 try { 157 // loginContext may be null in tests 158 if (loginContext != null) { 159 loginContext.logout(); 160 } 161 } catch (LoginException e) { 162 throw new NuxeoException(e); 163 } 164 } 165 } finally { 166 isUnrestricted = false; 167 if (Framework.isTestModeSet() && sessionIsAlreadyUnrestricted) { 168 session.save(); 169 } 170 } 171 } 172 173 /** 174 * This method will be called by {@link #runUnrestricted()} with {@link #session} available as an unrestricted 175 * session. 176 * <p> 177 * It can also be called directly in which case the {@link #session} available will be the one passed to 178 * {@code #UnrestrictedSessionRunner(CoreSession)}. 179 */ 180 public abstract void run(); 181 182}