/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.zeppelin.service;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.notebook.Notebook;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import sun.security.acl.PrincipalImpl;

@RunWith(PowerMockRunner.class)
@PrepareForTest(org.apache.shiro.SecurityUtils.class)
public class ShiroAuthenticationServiceTest {
  @Mock
  org.apache.shiro.subject.Subject subject;

  ShiroAuthenticationService shiroSecurityService;
  ZeppelinConfiguration zeppelinConfiguration;

  @Before
  public void setup() throws Exception {
    zeppelinConfiguration = ZeppelinConfiguration.create();
    shiroSecurityService = new ShiroAuthenticationService(zeppelinConfiguration);
  }

  @Test
  public void canGetPrincipalName()  {
    String expectedName = "java.security.Principal.getName()";
    setupPrincipalName(expectedName);
    assertEquals(expectedName, shiroSecurityService.getPrincipal());
  }

  @Test
  public void testUsernameForceLowerCase() throws IOException, InterruptedException {
    String expectedName = "java.security.Principal.getName()";
    System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_USERNAME_FORCE_LOWERCASE
        .getVarName(), String.valueOf(true));
    setupPrincipalName(expectedName);
    assertEquals(expectedName.toLowerCase(), shiroSecurityService.getPrincipal());
    System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_USERNAME_FORCE_LOWERCASE
        .getVarName(), String.valueOf(false));
  }

  private void setupPrincipalName(String expectedName) {
    PowerMockito.mockStatic(org.apache.shiro.SecurityUtils.class);
    when(org.apache.shiro.SecurityUtils.getSubject()).thenReturn(subject);
    when(subject.isAuthenticated()).thenReturn(true);
    when(subject.getPrincipal()).thenReturn(new PrincipalImpl(expectedName));

    Notebook notebook = Mockito.mock(Notebook.class);
    try {
      when(notebook.getConf())
          .thenReturn(new ZeppelinConfiguration(this.getClass().getResource("/zeppelin-site.xml")));
    } catch (ConfigurationException e) {
      e.printStackTrace();
    }
  }

  private void setFinalStatic(Field field, Object newValue)
      throws NoSuchFieldException, IllegalAccessException {
    field.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, newValue);
  }


}

@@ -1099,16 +1099,48 @@
 odifier;
+%0Aimport java.security.Principal;
 %0A%0Aimport
@@ -1601,47 +1601,8 @@
 ner;
-%0Aimport sun.security.acl.PrincipalImpl;
 %0A%0A@R
@@ -3156,16 +3156,20 @@
 urn(new 
+Test
 Principa
@@ -3173,12 +3173,8 @@
 ipal
-Impl
 (exp
@@ -3832,12 +3832,333 @@
 e);%0A  %7D%0A
-%0A
+  public class TestPrincipal implements Principal %7B%0A%0A    private String username;%0A%0A    public TestPrincipal(String username) %7B%0A      this.username = username;%0A    %7D%0A%0A    public String getUsername() %7B%0A      return username;%0A    %7D%0A%0A    @Override%0A    public String getName() %7B%0A      return String.valueOf(username);%0A    %7D%0A  %7D
 %0A%7D%0A

Remove PrincipalImpl, which is not part of the java API